diff --git a/build/three.js b/build/three.js index 4e506e39133e84..c2cd9fe63b055f 100644 --- a/build/three.js +++ b/build/three.js @@ -18,14 +18,23 @@ if ( typeof module === 'object' ) { if ( Math.sign === undefined ) { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign + Math.sign = function ( x ) { - return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0; + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : +x; }; } + +// set the default log handlers +THREE.log = function() { console.log.apply( console, arguments ); } +THREE.warn = function() { console.warn.apply( console, arguments ); } +THREE.error = function() { console.error.apply( console, arguments ); } + + // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; @@ -151,6 +160,7 @@ THREE.UnsignedShortType = 1012; THREE.IntType = 1013; THREE.UnsignedIntType = 1014; THREE.FloatType = 1015; +THREE.HalfFloatType = 1025; // Pixel types @@ -189,25 +199,25 @@ THREE.RGBA_PVRTC_2BPPV1_Format = 2103; THREE.Projector = function () { - console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); + THREE.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); this.projectVector = function ( vector, camera ) { - console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); + THREE.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); vector.project( camera ); }; this.unprojectVector = function ( vector, camera ) { - console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); + THREE.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); vector.unproject( camera ); }; this.pickingRay = function ( vector, camera ) { - console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); + THREE.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); }; @@ -215,7 +225,7 @@ THREE.Projector = function () { THREE.CanvasRenderer = function () { - console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); + THREE.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); this.domElement = document.createElement( 'canvas' ); this.clear = function () {}; @@ -402,21 +412,27 @@ THREE.Color.prototype = { }, - copyGammaToLinear: function ( color ) { + copyGammaToLinear: function ( color, gammaFactor ) { + + if ( gammaFactor === undefined ) gammaFactor = 2.0; - this.r = color.r * color.r; - this.g = color.g * color.g; - this.b = color.b * color.b; + this.r = Math.pow( color.r, gammaFactor ); + this.g = Math.pow( color.g, gammaFactor ); + this.b = Math.pow( color.b, gammaFactor ); return this; }, - copyLinearToGamma: function ( color ) { + copyLinearToGamma: function ( color, gammaFactor ) { - this.r = Math.sqrt( color.r ); - this.g = Math.sqrt( color.g ); - this.b = Math.sqrt( color.b ); + if ( gammaFactor === undefined ) gammaFactor = 2.0; + + var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; + + this.r = Math.pow( color.r, safeInverse ); + this.g = Math.pow( color.g, safeInverse ); + this.b = Math.pow( color.b, safeInverse ); return this; @@ -595,10 +611,16 @@ THREE.Color.prototype = { }, - toArray: function () { + toArray: function ( array, offset ) { - return [ this.r, this.g, this.b ]; + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; + + return array; }, clone: function () { @@ -1001,7 +1023,7 @@ THREE.Quaternion.prototype = { if ( p !== undefined ) { - console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + THREE.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); return this.multiplyQuaternions( q, p ); } @@ -1030,7 +1052,7 @@ THREE.Quaternion.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + THREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); return vector.applyQuaternion( this ); }, @@ -1241,7 +1263,7 @@ THREE.Vector2.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -1253,19 +1275,19 @@ THREE.Vector2.prototype = { }, - addVectors: function ( a, b ) { + addScalar: function ( s ) { - this.x = a.x + b.x; - this.y = a.y + b.y; + this.x += s; + this.y += s; return this; }, - addScalar: function ( s ) { + addVectors: function ( a, b ) { - this.x += s; - this.y += s; + this.x = a.x + b.x; + this.y = a.y + b.y; return this; @@ -1275,7 +1297,7 @@ THREE.Vector2.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -1287,6 +1309,15 @@ THREE.Vector2.prototype = { }, + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + + return this; + + }, + subVectors: function ( a, b ) { this.x = a.x - b.x; @@ -1534,9 +1565,9 @@ THREE.Vector2.prototype = { lerpVectors: function ( v1, v2, alpha ) { - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - return this; + return this; }, @@ -1571,14 +1602,14 @@ THREE.Vector2.prototype = { fromAttribute: function ( attribute, index, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset === undefined ) offset = 0; - index = index * attribute.itemSize + offset; + index = index * attribute.itemSize + offset; - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; - return this; + return this; }, @@ -1687,7 +1718,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -1724,7 +1755,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -1736,6 +1767,16 @@ THREE.Vector3.prototype = { return this; }, + + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + + return this; + + }, subVectors: function ( a, b ) { @@ -1751,7 +1792,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); return this.multiplyVectors( v, w ); } @@ -1792,7 +1833,7 @@ THREE.Vector3.prototype = { if ( euler instanceof THREE.Euler === false ) { - console.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); + THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } @@ -2193,9 +2234,9 @@ THREE.Vector3.prototype = { lerpVectors: function ( v1, v2, alpha ) { - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - return this; + return this; }, @@ -2203,7 +2244,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); return this.crossVectors( v, w ); } @@ -2310,19 +2351,19 @@ THREE.Vector3.prototype = { setEulerFromRotationMatrix: function ( m, order ) { - console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); + THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); }, setEulerFromQuaternion: function ( q, order ) { - console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); + THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); }, getPositionFromMatrix: function ( m ) { - console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); + THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); return this.setFromMatrixPosition( m ); @@ -2330,14 +2371,14 @@ THREE.Vector3.prototype = { getScaleFromMatrix: function ( m ) { - console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); + THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); return this.setFromMatrixScale( m ); }, getColumnFromMatrix: function ( index, matrix ) { - console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); + THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); return this.setFromMatrixColumn( index, matrix ); @@ -2367,7 +2408,7 @@ THREE.Vector3.prototype = { }, setFromMatrixColumn: function ( index, matrix ) { - + var offset = index * 4; var me = matrix.elements; @@ -2413,15 +2454,15 @@ THREE.Vector3.prototype = { fromAttribute: function ( attribute, index, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset === undefined ) offset = 0; - index = index * attribute.itemSize + offset; + index = index * attribute.itemSize + offset; - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; - this.z = attribute.array[ index + 2 ]; + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + this.z = attribute.array[ index + 2 ]; - return this; + return this; }, @@ -2542,7 +2583,7 @@ THREE.Vector4.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -2582,7 +2623,7 @@ THREE.Vector4.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -2596,6 +2637,17 @@ THREE.Vector4.prototype = { }, + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; + + return this; + + }, + subVectors: function ( a, b ) { this.x = a.x - b.x; @@ -2942,49 +2994,49 @@ THREE.Vector4.prototype = { } )(), - floor: function () { + 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 ); + 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; + return this; - }, + }, - ceil: function () { + 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 ); + 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; + return this; - }, + }, - round: function () { + 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 ); + 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; + return this; - }, + }, - roundToZero: function () { + 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 ); + 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; + return this; - }, + }, negate: function () { @@ -3054,9 +3106,9 @@ THREE.Vector4.prototype = { lerpVectors: function ( v1, v2, alpha ) { - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - return this; + return this; }, @@ -3095,16 +3147,16 @@ THREE.Vector4.prototype = { fromAttribute: function ( attribute, index, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset === undefined ) offset = 0; - index = index * attribute.itemSize + offset; + index = index * attribute.itemSize + offset; - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; - this.z = attribute.array[ index + 2 ]; - this.w = attribute.array[ index + 3 ]; + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + this.z = attribute.array[ index + 2 ]; + this.w = attribute.array[ index + 3 ]; - return this; + return this; }, @@ -3332,7 +3384,7 @@ THREE.Euler.prototype = { } else { - console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) + THREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) } @@ -3400,10 +3452,17 @@ THREE.Euler.prototype = { }, - toArray: function () { + toArray: function ( array, offset ) { - return [ this._x, this._y, this._z, this._order ]; + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; + + return array; }, toVector3: function ( optionalResult ) { @@ -4180,7 +4239,7 @@ THREE.Matrix3 = function () { if ( arguments.length > 0 ) { - console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); + THREE.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); } @@ -4234,14 +4293,14 @@ THREE.Matrix3.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); return vector.applyMatrix3( this ); }, multiplyVector3Array: function ( a ) { - console.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + THREE.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); return this.applyToVector3Array( a ); }, @@ -4255,7 +4314,7 @@ THREE.Matrix3.prototype = { if ( offset === undefined ) offset = 0; if ( length === undefined ) length = array.length; - for ( var i = 0, j = offset, il; i < length; i += 3, j += 3 ) { + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { v1.x = array[ j ]; v1.y = array[ j + 1 ]; @@ -4331,7 +4390,7 @@ THREE.Matrix3.prototype = { } else { - console.warn( msg ); + THREE.warn( msg ); } @@ -4463,7 +4522,7 @@ THREE.Matrix4 = function () { if ( arguments.length > 0 ) { - console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); + THREE.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); } @@ -4511,7 +4570,7 @@ THREE.Matrix4.prototype = { extractPosition: function ( m ) { - console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); + THREE.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); return this.copyPosition( m ); }, @@ -4531,15 +4590,15 @@ THREE.Matrix4.prototype = { extractBasis: function ( xAxis, yAxis, zAxis ) { - var te = this.elements; + 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; + return this; - }, + }, makeBasis: function ( xAxis, yAxis, zAxis ) { @@ -4550,7 +4609,7 @@ THREE.Matrix4.prototype = { 0, 0, 0, 1 ); - return this; + return this; }, @@ -4589,7 +4648,7 @@ THREE.Matrix4.prototype = { if ( euler instanceof THREE.Euler === false ) { - console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); + THREE.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } @@ -4715,7 +4774,7 @@ THREE.Matrix4.prototype = { setRotationFromQuaternion: function ( q ) { - console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); + THREE.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); return this.makeRotationFromQuaternion( q ); @@ -4802,7 +4861,7 @@ THREE.Matrix4.prototype = { if ( n !== undefined ) { - console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); return this.multiplyMatrices( m, n ); } @@ -4881,21 +4940,21 @@ THREE.Matrix4.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); return vector.applyProjection( this ); }, multiplyVector4: function ( vector ) { - console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, multiplyVector3Array: function ( a ) { - console.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); return this.applyToVector3Array( a ); }, @@ -4909,7 +4968,7 @@ THREE.Matrix4.prototype = { if ( offset === undefined ) offset = 0; if ( length === undefined ) length = array.length; - for ( var i = 0, j = offset, il; i < length; i += 3, j += 3 ) { + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { v1.x = array[ j ]; v1.y = array[ j + 1 ]; @@ -4931,7 +4990,7 @@ THREE.Matrix4.prototype = { rotateAxis: function ( v ) { - console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); v.transformDirection( this ); @@ -4939,7 +4998,7 @@ THREE.Matrix4.prototype = { crossVector: function ( vector ) { - console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, @@ -5045,7 +5104,7 @@ THREE.Matrix4.prototype = { return function () { - console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); var te = this.elements; return v1.set( te[ 12 ], te[ 13 ], te[ 14 ] ); @@ -5098,7 +5157,7 @@ THREE.Matrix4.prototype = { if ( det == 0 ) { - var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0"; + var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; if ( throwOnInvertible || false ) { @@ -5106,7 +5165,7 @@ THREE.Matrix4.prototype = { } else { - console.warn( msg ); + THREE.warn( msg ); } @@ -5123,31 +5182,31 @@ THREE.Matrix4.prototype = { translate: function ( v ) { - console.warn( 'THREE.Matrix4: .translate() has been removed.' ); + THREE.error( 'THREE.Matrix4: .translate() has been removed.' ); }, rotateX: function ( angle ) { - console.warn( 'THREE.Matrix4: .rotateX() has been removed.' ); + THREE.error( 'THREE.Matrix4: .rotateX() has been removed.' ); }, rotateY: function ( angle ) { - console.warn( 'THREE.Matrix4: .rotateY() has been removed.' ); + THREE.error( 'THREE.Matrix4: .rotateY() has been removed.' ); }, rotateZ: function ( angle ) { - console.warn( 'THREE.Matrix4: .rotateZ() has been removed.' ); + THREE.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); }, rotateByAxis: function ( axis, angle ) { - console.warn( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); + THREE.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); }, @@ -5775,7 +5834,7 @@ THREE.Ray.prototype = { }(), - intersectBox: function ( box , optionalTarget ) { + intersectBox: function ( box, optionalTarget ) { // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ @@ -5980,7 +6039,7 @@ THREE.Sphere.prototype = { var box = new THREE.Box3(); - return function ( points, optionalCenter ) { + return function ( points, optionalCenter ) { var center = this.center; @@ -6006,7 +6065,7 @@ THREE.Sphere.prototype = { return this; - }; + }; }(), @@ -6666,6 +6725,20 @@ THREE.Math = { return ( value & ( value - 1 ) ) === 0 && value !== 0; + }, + + nextPowerOfTwo: function ( value ) { + + value --; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + value ++; + + return value; + } }; @@ -6799,7 +6872,7 @@ THREE.Spline = function ( points ) { var i, j, index, indexCurrent, indexNext, - linearDistance, realDistance, + realDistance, sampling, position, newpoints = [], tmpVec = new THREE.Vector3(), @@ -7312,7 +7385,7 @@ THREE.EventDispatcher.prototype = { } else { - console.error( 'THREE.Raycaster: Unsupported camera type.' ); + THREE.error( 'THREE.Raycaster: Unsupported camera type.' ); } @@ -7336,7 +7409,7 @@ THREE.EventDispatcher.prototype = { if ( objects instanceof Array === false ) { - console.log( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); + THREE.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); return intersects; } @@ -7380,8 +7453,6 @@ THREE.Object3D = function () { this.up = THREE.Object3D.DefaultUp.clone(); - var scope = this; - var position = new THREE.Vector3(); var rotation = new THREE.Euler(); var quaternion = new THREE.Quaternion(); @@ -7414,7 +7485,7 @@ THREE.Object3D = function () { scale: { enumerable: true, value: scale - }, + } } ); this.rotationAutoUpdate = true; @@ -7431,6 +7502,7 @@ THREE.Object3D = function () { this.receiveShadow = false; this.frustumCulled = true; + this.renderOrder = 0; this.userData = {}; @@ -7444,7 +7516,7 @@ THREE.Object3D.prototype = { get eulerOrder () { - console.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); + THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); return this.rotation.order; @@ -7452,7 +7524,7 @@ THREE.Object3D.prototype = { set eulerOrder ( value ) { - console.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); + THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); this.rotation.order = value; @@ -7460,13 +7532,13 @@ THREE.Object3D.prototype = { get useQuaternion () { - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); }, set useQuaternion ( value ) { - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); }, @@ -7584,7 +7656,7 @@ THREE.Object3D.prototype = { translate: function ( distance, axis ) { - console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); + THREE.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); return this.translateOnAxis( axis, distance ); }, @@ -7663,7 +7735,7 @@ THREE.Object3D.prototype = { if ( arguments.length > 1 ) { - for ( var i = 0; i < arguments.length; i++ ) { + for ( var i = 0; i < arguments.length; i ++ ) { this.add( arguments[ i ] ); @@ -7675,7 +7747,7 @@ THREE.Object3D.prototype = { if ( object === this ) { - console.error( "THREE.Object3D.add:", object, "can't be added as a child of itself." ); + THREE.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); return this; } @@ -7695,7 +7767,7 @@ THREE.Object3D.prototype = { } else { - console.error( "THREE.Object3D.add:", object, "is not an instance of THREE.Object3D." ); + THREE.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); } @@ -7707,7 +7779,7 @@ THREE.Object3D.prototype = { if ( arguments.length > 1 ) { - for ( var i = 0; i < arguments.length; i++ ) { + for ( var i = 0; i < arguments.length; i ++ ) { this.remove( arguments[ i ] ); @@ -7729,33 +7801,33 @@ THREE.Object3D.prototype = { }, - getChildByName: function ( name, recursive ) { + getChildByName: function ( name ) { - console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name, recursive ); + THREE.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name ); }, - getObjectById: function ( id, recursive ) { + getObjectById: function ( id ) { - return this.getObjectByProperty( 'id', id, recursive ); + return this.getObjectByProperty( 'id', id ); }, - getObjectByName: function ( name, recursive ) { + getObjectByName: function ( name ) { - return this.getObjectByProperty( 'name', name, recursive ); + return this.getObjectByProperty( 'name', name ); }, - getObjectByProperty: function ( name, value, recursive ) { + getObjectByProperty: function ( name, value ) { if ( this[ name ] === value ) return this; for ( var i = 0, l = this.children.length; i < l; i ++ ) { var child = this.children[ i ]; - var object = child.getObjectByProperty( name, value, recursive ); + var object = child.getObjectByProperty( name, value ); if ( object !== undefined ) { @@ -8038,6 +8110,7 @@ THREE.Object3D.prototype = { data.color = object.color.getHex(); data.intensity = object.intensity; data.distance = object.distance; + data.decay = object.decay; } else if ( object instanceof THREE.SpotLight ) { @@ -8046,21 +8119,19 @@ THREE.Object3D.prototype = { data.distance = object.distance; data.angle = object.angle; data.exponent = object.exponent; + data.decay = object.decay; } else if ( object instanceof THREE.HemisphereLight ) { data.color = object.color.getHex(); data.groundColor = object.groundColor.getHex(); - } else if ( object instanceof THREE.Mesh ) { + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) { data.geometry = parseGeometry( object.geometry ); data.material = parseMaterial( object.material ); - } else if ( object instanceof THREE.Line ) { - - data.geometry = parseGeometry( object.geometry ); - data.material = parseMaterial( object.material ); + if ( object instanceof THREE.Line ) data.mode = object.mode; } else if ( object instanceof THREE.Sprite ) { @@ -8213,7 +8284,7 @@ THREE.Face3.prototype = { 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.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ) return new THREE.Face3( a, b, c, normal, color, materialIndex ); }; @@ -8254,11 +8325,15 @@ THREE.BufferAttribute.prototype = { } + return this; + }, - set: function ( value ) { + set: function ( value, offset ) { + + if ( offset === undefined ) offset = 0; - this.array.set( value ); + this.array.set( value, offset ); return this; @@ -8336,21 +8411,21 @@ THREE.BufferAttribute.prototype = { THREE.Int8Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Uint8Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Uint8ClampedAttribute = function ( data, itemSize ) { - console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); @@ -8358,46 +8433,70 @@ THREE.Uint8ClampedAttribute = function ( data, itemSize ) { THREE.Int16Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Uint16Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Int32Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Uint32Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Float32Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Float64Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; +// File:src/core/DynamicBufferAttribute.js + +/** + * @author benaadams / https://twitter.com/ben_a_adams + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.DynamicBufferAttribute = function ( array, itemSize ) { + + THREE.BufferAttribute.call( this, array, itemSize ); + + this.updateRange = { offset: 0, count: -1 }; + +}; + +THREE.DynamicBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); +THREE.DynamicBufferAttribute.prototype.constructor = THREE.DynamicBufferAttribute; + +THREE.DynamicBufferAttribute.prototype.clone = function () { + + return new THREE.DynamicBufferAttribute( new this.array.constructor( this.array ), this.itemSize ); + +}; + // File:src/core/BufferGeometry.js /** @@ -8433,7 +8532,7 @@ THREE.BufferGeometry.prototype = { if ( attribute instanceof THREE.BufferAttribute === false ) { - console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); + THREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] }; @@ -8486,11 +8585,29 @@ THREE.BufferGeometry.prototype = { } + if ( this.boundingBox !== null ) { + + this.computeBoundingBox(); + + } + + if ( this.boundingSphere !== null ) { + + this.computeBoundingSphere(); + + } + }, center: function () { - // TODO + this.computeBoundingBox(); + + var offset = this.boundingBox.center().negate(); + + this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); + + return offset; }, @@ -8679,7 +8796,7 @@ THREE.BufferGeometry.prototype = { if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' ); + THREE.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' ); } @@ -8733,7 +8850,7 @@ THREE.BufferGeometry.prototype = { if ( isNaN( this.boundingSphere.radius ) ) { - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' ); + THREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' ); } @@ -8878,7 +8995,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.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' ); return; } @@ -9051,24 +9168,18 @@ THREE.BufferGeometry.prototype = { }, /* - 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. + 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. + size - Defaults to 65535, but allows for larger or smaller chunks. */ - computeOffsets: function ( indexBufferSize ) { + computeOffsets: function ( size ) { - var size = indexBufferSize; - if ( indexBufferSize === undefined ) - size = 65535; //WebGL limits type of index buffer values to 16-bit. - - var s = Date.now(); + if ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit. var indices = this.attributes.index.array; var vertices = this.attributes.position.array; - var verticesCount = ( vertices.length / 3 ); var facesCount = ( indices.length / 3 ); /* @@ -9148,7 +9259,8 @@ THREE.BufferGeometry.prototype = { /* 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; + this.offsets = offsets; // TODO: Deprecate + this.drawcalls = offsets; /* var orderTime = Date.now(); @@ -9166,7 +9278,7 @@ THREE.BufferGeometry.prototype = { if ( geometry instanceof THREE.BufferGeometry === false ) { - console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); + THREE.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); return; } @@ -9286,13 +9398,7 @@ THREE.BufferGeometry.prototype = { var attribute = attributes[ key ]; - var array = [], typeArray = attribute.array; - - for ( var i = 0, l = typeArray.length; i < l; i ++ ) { - - array[ i ] = typeArray[ i ]; - - } + var array = Array.prototype.slice.call( attribute.array ); output.data.attributes[ key ] = { itemSize: attribute.itemSize, @@ -9445,18 +9551,21 @@ THREE.Geometry.prototype = { } - if ( this.boundingBox instanceof THREE.Box3 ) { + if ( this.boundingBox !== null ) { this.computeBoundingBox(); } - if ( this.boundingSphere instanceof THREE.Sphere ) { + if ( this.boundingSphere !== null ) { this.computeBoundingSphere(); } + this.verticesNeedUpdate = true; + this.normalsNeedUpdate = true; + }, fromBufferGeometry: function ( geometry ) { @@ -9515,9 +9624,33 @@ THREE.Geometry.prototype = { if ( indices !== undefined ) { - for ( var i = 0; i < indices.length; i += 3 ) { + var drawcalls = geometry.drawcalls; - addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + if ( drawcalls.length > 0 ) { + + for ( var i = 0; i < drawcalls.length; i ++ ) { + + var drawcall = drawcalls[ i ]; + + var start = drawcall.start; + var count = drawcall.count; + var index = drawcall.index; + + for ( var j = start, jl = start + count; j < jl; j += 3 ) { + + addFace( index + indices[ j ], index + indices[ j + 1 ], index + indices[ j + 2 ] ); + + } + + } + + } else { + + for ( var i = 0; i < indices.length; i += 3 ) { + + addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + + } } @@ -9553,13 +9686,9 @@ THREE.Geometry.prototype = { this.computeBoundingBox(); - var offset = new THREE.Vector3(); - - offset.addVectors( this.boundingBox.min, this.boundingBox.max ); - offset.multiplyScalar( - 0.5 ); + var offset = this.boundingBox.center().negate(); - this.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); - this.computeBoundingBox(); + this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); return offset; @@ -9606,9 +9735,8 @@ THREE.Geometry.prototype = { // 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(); + var vA, vB, vC; + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { @@ -9782,7 +9910,7 @@ THREE.Geometry.prototype = { // based on http://www.terathon.com/code/tangent.html // tangents go to vertices - var f, fl, v, vl, i, il, vertexIndex, + var f, fl, v, vl, i, vertexIndex, face, uv, vA, vB, vC, uvA, uvB, uvC, x1, x2, y1, y2, z1, z2, s1, s2, t1, t2, r, t, test, @@ -9929,7 +10057,7 @@ THREE.Geometry.prototype = { if ( geometry instanceof THREE.Geometry === false ) { - console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); + THREE.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); return; } @@ -10039,7 +10167,7 @@ THREE.Geometry.prototype = { if ( mesh instanceof THREE.Mesh === false ) { - console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); + THREE.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); return; } @@ -10064,8 +10192,8 @@ THREE.Geometry.prototype = { 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; + var i, il, face; + var indices, j, jl; for ( i = 0, il = this.vertices.length; i < il; i ++ ) { @@ -10900,7 +11028,7 @@ THREE.DirectionalLight = function ( color, intensity ) { this.shadowCascadeHeight = [ 512, 512, 512 ]; this.shadowCascadeNearZ = [ - 1.000, 0.990, 0.998 ]; - this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; + this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; this.shadowCascadeArray = []; @@ -11006,7 +11134,7 @@ THREE.HemisphereLight.prototype.clone = function () { * @author mrdoob / http://mrdoob.com/ */ -THREE.PointLight = function ( color, intensity, distance ) { +THREE.PointLight = function ( color, intensity, distance, decay ) { THREE.Light.call( this, color ); @@ -11014,6 +11142,7 @@ THREE.PointLight = function ( color, intensity, distance ) { this.intensity = ( intensity !== undefined ) ? intensity : 1; this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. }; @@ -11028,6 +11157,7 @@ THREE.PointLight.prototype.clone = function () { light.intensity = this.intensity; light.distance = this.distance; + light.decay = this.decay; return light; @@ -11039,7 +11169,7 @@ THREE.PointLight.prototype.clone = function () { * @author alteredq / http://alteredqualia.com/ */ -THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { +THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) { THREE.Light.call( this, color ); @@ -11052,6 +11182,7 @@ THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { this.distance = ( distance !== undefined ) ? distance : 0; this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; this.exponent = ( exponent !== undefined ) ? exponent : 10; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. this.castShadow = false; this.onlyShadow = false; @@ -11094,6 +11225,7 @@ THREE.SpotLight.prototype.clone = function () { light.distance = this.distance; light.angle = this.angle; light.exponent = this.exponent; + light.decay = this.decay; light.castShadow = this.castShadow; light.onlyShadow = this.onlyShadow; @@ -11122,15 +11254,9 @@ THREE.SpotLight.prototype.clone = function () { * @author mrdoob / http://mrdoob.com/ */ -THREE.Cache = function () { - - this.files = {}; - -}; - -THREE.Cache.prototype = { +THREE.Cache = { - constructor: THREE.Cache, + files: {}, add: function ( key, file ) { @@ -11392,12 +11518,18 @@ THREE.Loader.prototype = { } - if ( m.transparent !== undefined || m.opacity < 1.0 ) { + if ( m.transparent !== undefined ) { mpars.transparent = m.transparent; } + if ( m.opacity !== undefined && m.opacity < 1.0 ) { + + mpars.transparent = true; + + } + if ( m.depthTest !== undefined ) { mpars.depthTest = m.depthTest; @@ -11474,9 +11606,16 @@ THREE.Loader.prototype = { // modifiers - if ( m.transparency ) { + if ( m.transparency !== undefined ) { + + console.warn( 'THREE.Loader: transparency has been renamed to opacity' ); + m.opacity = m.transparency; + + } + + if ( m.opacity !== undefined ) { - mpars.opacity = m.transparency; + mpars.opacity = m.opacity; } @@ -11587,7 +11726,6 @@ THREE.Loader.Handlers = { THREE.XHRLoader = function ( manager ) { - this.cache = new THREE.Cache(); this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; @@ -11600,7 +11738,7 @@ THREE.XHRLoader.prototype = { var scope = this; - var cached = scope.cache.get( url ); + var cached = THREE.Cache.get( url ); if ( cached !== undefined ) { @@ -11614,7 +11752,7 @@ THREE.XHRLoader.prototype = { request.addEventListener( 'load', function ( event ) { - scope.cache.add( url, this.response ); + THREE.Cache.add( url, this.response ); if ( onLoad ) onLoad( this.response ); @@ -11673,7 +11811,6 @@ THREE.XHRLoader.prototype = { THREE.ImageLoader = function ( manager ) { - this.cache = new THREE.Cache(); this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; @@ -11686,7 +11823,7 @@ THREE.ImageLoader.prototype = { var scope = this; - var cached = scope.cache.get( url ); + var cached = THREE.Cache.get( url ); if ( cached !== undefined ) { @@ -11697,18 +11834,15 @@ THREE.ImageLoader.prototype = { var image = document.createElement( 'img' ); - if ( onLoad !== undefined ) { - - image.addEventListener( 'load', function ( event ) { + image.addEventListener( 'load', function ( event ) { - scope.cache.add( url, this ); + THREE.Cache.add( url, this ); - onLoad( this ); - scope.manager.itemEnd( url ); - - }, false ); + if ( onLoad ) onLoad( this ); + + scope.manager.itemEnd( url ); - } + }, false ); if ( onProgress !== undefined ) { @@ -11768,8 +11902,6 @@ THREE.JSONLoader.prototype.constructor = THREE.JSONLoader; 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 ); @@ -11794,18 +11926,23 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex if ( xhr.responseText ) { var json = JSON.parse( xhr.responseText ); + var metadata = json.metadata; - if ( json.metadata !== undefined && json.metadata.version >= 4 ) { + if ( metadata !== undefined ) { - console.error( 'THREE.JSONLoader: "' + url + '" should be loaded with THREE.ObjectLoader instead.' ); - return; + if ( metadata.type === 'object' ) { - } + THREE.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); + return; + + } + + if ( metadata.type === 'scene' ) { - if ( json.metadata !== undefined && json.metadata.type === 'scene' ) { + THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.' ); + return; - console.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); - return; + } } @@ -11814,7 +11951,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.error( 'THREE.JSONLoader: ' + url + ' seems to be unreachable or the file is empty.' ); } @@ -11826,7 +11963,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex } else { - console.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); + THREE.error( 'THREE.JSONLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' ); } @@ -11864,8 +12001,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { - var scope = this, - geometry = new THREE.Geometry(), + var geometry = new THREE.Geometry(), scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; parseModel( scale ); @@ -11897,7 +12033,7 @@ THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor, - vertex, face, faceA, faceB, color, hex, normal, + vertex, face, faceA, faceB, hex, normal, uvLayer, uv, u, v, @@ -12213,7 +12349,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.warn( 'THREE.JSONLoader: When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); } @@ -12387,7 +12523,7 @@ THREE.BufferGeometryLoader.prototype = { var geometry = new THREE.BufferGeometry(); - var attributes = json.attributes; + var attributes = json.data.attributes; for ( var key in attributes ) { @@ -12398,7 +12534,7 @@ THREE.BufferGeometryLoader.prototype = { } - var offsets = json.offsets; + var offsets = json.data.offsets; if ( offsets !== undefined ) { @@ -12406,7 +12542,7 @@ THREE.BufferGeometryLoader.prototype = { } - var boundingSphere = json.boundingSphere; + var boundingSphere = json.data.boundingSphere; if ( boundingSphere !== undefined ) { @@ -12483,6 +12619,10 @@ THREE.MaterialLoader.prototype = { if ( json.transparent !== undefined ) material.transparent = json.transparent; if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + // for PointCloudMaterial + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + if ( json.materials !== undefined ) { for ( var i = 0, l = json.materials.length; i < l; i ++ ) { @@ -12508,6 +12648,7 @@ THREE.MaterialLoader.prototype = { THREE.ObjectLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.texturePath = ''; }; @@ -12517,30 +12658,55 @@ THREE.ObjectLoader.prototype = { load: function ( url, onLoad, onProgress, onError ) { + if ( this.texturePath === '' ) { + + this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); + + } + 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 ) ) ); + scope.parse( JSON.parse( text ), onLoad ); }, onProgress, onError ); }, + setTexturePath: function ( value ) { + + this.texturePath = value; + + }, + setCrossOrigin: function ( value ) { this.crossOrigin = value; }, - parse: function ( json ) { + parse: function ( json, onLoad ) { var geometries = this.parseGeometries( json.geometries ); - var materials = this.parseMaterials( json.materials ); + + var images = this.parseImages( json.images, function () { + + if ( onLoad !== undefined ) onLoad( object ); + + } ); + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); var object = this.parseObject( json.object, geometries, materials ); + if ( json.images === undefined || json.images.length === 0 ) { + + if ( onLoad !== undefined ) onLoad( object ); + + } + return object; }, @@ -12562,8 +12728,9 @@ THREE.ObjectLoader.prototype = { switch ( data.type ) { case 'PlaneGeometry': + case 'PlaneBufferGeometry': - geometry = new THREE.PlaneGeometry( + geometry = new THREE[ data.type ]( data.width, data.height, data.widthSegments, @@ -12659,7 +12826,7 @@ THREE.ObjectLoader.prototype = { case 'BufferGeometry': - geometry = bufferGeometryLoader.parse( data.data ); + geometry = bufferGeometryLoader.parse( data ); break; @@ -12685,12 +12852,24 @@ THREE.ObjectLoader.prototype = { }, - parseMaterials: function ( json ) { + parseMaterials: function ( json, textures ) { var materials = {}; if ( json !== undefined ) { + var getTexture = function ( name ) { + + if ( textures[ name ] === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: Undefined texture', name ); + + } + + return textures[ name ]; + + }; + var loader = new THREE.MaterialLoader(); for ( var i = 0, l = json.length; i < l; i ++ ) { @@ -12702,6 +12881,54 @@ THREE.ObjectLoader.prototype = { if ( data.name !== undefined ) material.name = data.name; + if ( data.map !== undefined ) { + + material.map = getTexture( data.map ); + + } + + if ( data.bumpMap !== undefined ) { + + material.bumpMap = getTexture( data.bumpMap ); + if ( data.bumpScale ) { + material.bumpScale = new THREE.Vector2( data.bumpScale, data.bumpScale ); + } + + } + + if ( data.alphaMap !== undefined ) { + + material.alphaMap = getTexture( data.alphaMap ); + + } + + if ( data.envMap !== undefined ) { + + material.envMap = getTexture( data.envMap ); + + } + + if ( data.normalMap !== undefined ) { + + material.normalMap = getTexture( data.normalMap ); + if ( data.normalScale ) { + material.normalScale = new THREE.Vector2( data.normalScale, data.normalScale ); + } + + } + + if ( data.lightMap !== undefined ) { + + material.lightMap = getTexture( data.lightMap ); + + } + + if ( data.specularMap !== undefined ) { + + material.specularMap = getTexture( data.specularMap ); + + } + materials[ data.uuid ] = material; } @@ -12712,6 +12939,94 @@ THREE.ObjectLoader.prototype = { }, + parseImages: function ( json, onLoad ) { + + var scope = this; + var images = {}; + + if ( json !== undefined && json.length > 0 ) { + + var manager = new THREE.LoadingManager( onLoad ); + + var loader = new THREE.ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); + + var loadImage = function ( url ) { + + scope.manager.itemStart( url ); + + return loader.load( url, function () { + + scope.manager.itemEnd( url ); + + } ); + + }; + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var image = json[ i ]; + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; + + images[ image.uuid ] = loadImage( path ); + + } + + } + + return images; + + }, + + parseTextures: function ( json, images ) { + + var textures = {}; + + if ( json !== undefined ) { + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var data = json[ i ]; + + if ( data.image === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: No "image" speficied for', data.uuid ); + + } + + if ( images[ data.image ] === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + + } + + var texture = new THREE.Texture( images[ data.image ] ); + texture.needsUpdate = true; + + texture.uuid = data.uuid; + + if ( data.name !== undefined ) texture.name = data.name; + if ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] ); + if ( data.minFilter !== undefined ) texture.minFilter = THREE[ data.minFilter ]; + if ( data.magFilter !== undefined ) texture.magFilter = THREE[ data.magFilter ]; + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + if ( data.wrap instanceof Array ) { + + texture.wrapS = THREE[ data.wrap[ 0 ] ]; + texture.wrapT = THREE[ data.wrap[ 1 ] ]; + + } + + textures[ data.uuid ] = texture; + + } + + } + + return textures; + + }, + parseObject: function () { var matrix = new THREE.Matrix4(); @@ -12720,6 +13035,30 @@ THREE.ObjectLoader.prototype = { var object; + var getGeometry = function ( name ) { + + if ( geometries[ name ] === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + + } + + return geometries[ name ]; + + }; + + var getMaterial = function ( name ) { + + if ( materials[ name ] === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: Undefined material', name ); + + } + + return materials[ name ]; + + }; + switch ( data.type ) { case 'Scene': @@ -12754,13 +13093,13 @@ 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 ); 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 ); break; @@ -12772,57 +13111,25 @@ THREE.ObjectLoader.prototype = { case 'Mesh': - var geometry = geometries[ data.geometry ]; - var material = materials[ data.material ]; - - if ( geometry === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined geometry', data.geometry ); - - } - - if ( material === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', data.material ); - - } - - object = new THREE.Mesh( geometry, material ); + object = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) ); break; case 'Line': - var geometry = geometries[ data.geometry ]; - var material = materials[ data.material ]; - - if ( geometry === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined geometry', data.geometry ); - - } - - if ( material === undefined ) { + object = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - console.warn( 'THREE.ObjectLoader: Undefined material', data.material ); + break; - } + case 'PointCloud': - object = new THREE.Line( geometry, material ); + object = new THREE.PointCloud( getGeometry( data.geometry ), getMaterial( data.material ) ); break; case 'Sprite': - var material = materials[ data.material ]; - - if ( material === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', data.material ); - - } - - object = new THREE.Sprite( material ); + object = new THREE.Sprite( getMaterial( data.material ) ); break; @@ -12958,7 +13265,7 @@ THREE.BinaryTextureLoader.prototype = { texture.image = texData.image; - } else if ( undefined !== texData.data ){ + } else if ( undefined !== texData.data ) { texture.image.width = texData.width; texture.image.height = texData.height; @@ -13063,7 +13370,7 @@ THREE.CompressedTextureLoader.prototype = { if ( loaded === 6 ) { - if (texDatas.mipmapCount == 1) + if (texDatas.mipmapCount == 1) texture.minFilter = THREE.LinearFilter; texture.format = texDatas.format; @@ -13172,6 +13479,8 @@ THREE.Material = function () { this.depthTest = true; this.depthWrite = true; + this.colorWrite = true; + this.polygonOffset = false; this.polygonOffsetFactor = 0; this.polygonOffsetUnits = 0; @@ -13182,7 +13491,7 @@ THREE.Material = function () { this.visible = true; - this.needsUpdate = true; + this._needsUpdate = true; }; @@ -13190,6 +13499,20 @@ THREE.Material.prototype = { constructor: THREE.Material, + get needsUpdate () { + + return this._needsUpdate; + + }, + + set needsUpdate ( value ) { + + if ( value === true ) this.update(); + + this._needsUpdate = value; + + }, + setValues: function ( values ) { if ( values === undefined ) return; @@ -13200,7 +13523,7 @@ THREE.Material.prototype = { if ( newValue === undefined ) { - console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); + THREE.warn( "THREE.Material: '" + key + "' parameter is undefined." ); continue; } @@ -13260,6 +13583,7 @@ THREE.Material.prototype = { output.color = this.color.getHex(); output.emissive = this.emissive.getHex(); if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; if ( this.side !== THREE.FrontSide ) output.side = this.side; @@ -13270,12 +13594,12 @@ THREE.Material.prototype = { output.specular = this.specular.getHex(); output.shininess = this.shininess; if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; if ( this.side !== THREE.FrontSide ) output.side = this.side; } else if ( this instanceof THREE.MeshNormalMaterial ) { - if ( this.shading !== THREE.FlatShading ) output.shading = this.shading; if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; if ( this.side !== THREE.FrontSide ) output.side = this.side; @@ -13284,6 +13608,15 @@ THREE.Material.prototype = { if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; if ( this.side !== THREE.FrontSide ) output.side = this.side; + } else if ( this instanceof THREE.PointCloudMaterial ) { + + output.size = this.size; + output.sizeAttenuation = this.sizeAttenuation; + output.color = this.color.getHex(); + + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + } else if ( this instanceof THREE.ShaderMaterial ) { output.uniforms = this.uniforms; @@ -13341,6 +13674,12 @@ THREE.Material.prototype = { }, + update: function () { + + this.dispatchEvent( { type: 'update' } ); + + }, + dispose: function () { this.dispatchEvent( { type: 'dispose' } ); @@ -13978,8 +14317,6 @@ THREE.MeshNormalMaterial = function ( parameters ) { this.type = 'MeshNormalMaterial'; - this.shading = THREE.FlatShading; - this.wireframe = false; this.wireframeLinewidth = 1; @@ -13998,8 +14335,6 @@ THREE.MeshNormalMaterial.prototype.clone = function () { THREE.Material.prototype.clone.call( this, material ); - material.shading = this.shading; - material.wireframe = this.wireframe; material.wireframeLinewidth = this.wireframeLinewidth; @@ -14139,14 +14474,14 @@ THREE.PointCloudMaterial.prototype.clone = function () { THREE.ParticleBasicMaterial = function ( parameters ) { - console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); + THREE.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); return new THREE.PointCloudMaterial( parameters ); }; THREE.ParticleSystemMaterial = function ( parameters ) { - console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' ); + THREE.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' ); return new THREE.PointCloudMaterial( parameters ); }; @@ -14367,6 +14702,7 @@ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, f this.uuid = THREE.Math.generateUUID(); this.name = ''; + this.sourceFile = ''; this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE; this.mipmaps = []; @@ -14709,7 +15045,7 @@ THREE.PointCloud.prototype.raycast = ( function () { } - for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { + for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { var start = offsets[ oi ].start; var count = offsets[ oi ].count; @@ -14775,7 +15111,7 @@ THREE.PointCloud.prototype.clone = function ( object ) { THREE.ParticleSystem = function ( geometry, material ) { - console.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); + THREE.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); return new THREE.PointCloud( geometry, material ); }; @@ -14795,7 +15131,7 @@ THREE.Line = function ( geometry, material, mode ) { this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); - this.mode = ( mode !== undefined ) ? mode : THREE.LineStrip; + this.mode = mode !== undefined ? mode : THREE.LineStrip; }; @@ -14856,7 +15192,7 @@ THREE.Line.prototype.raycast = ( function () { } - for ( var oi = 0; oi < offsets.length; oi++){ + for ( var oi = 0; oi < offsets.length; oi ++) { var start = offsets[ oi ].start; var count = offsets[ oi ].count; @@ -15029,7 +15365,7 @@ THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { } - console.log( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); + THREE.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); return 0; @@ -15070,7 +15406,7 @@ THREE.Mesh.prototype.raycast = ( function () { if ( geometry.boundingBox !== null ) { - if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { + if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { return; @@ -15101,7 +15437,7 @@ THREE.Mesh.prototype.raycast = ( function () { } - for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { + for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { var start = offsets[ oi ].start; var count = offsets[ oi ].count; @@ -15200,7 +15536,7 @@ THREE.Mesh.prototype.raycast = ( function () { var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial; var objectMaterials = isFaceMaterial === true ? this.material.materials : null; - var a, b, c, d; + var a, b, c; var precision = raycaster.precision; var vertices = geometry.vertices; @@ -15312,18 +15648,19 @@ THREE.Mesh.prototype.clone = function ( object, recursive ) { * @author ikerr / http://verold.com */ -THREE.Bone = function ( belongsToSkin ) { +THREE.Bone = function ( skin ) { THREE.Object3D.call( this ); - this.skin = belongsToSkin; + this.type = 'Bone'; + + this.skin = skin; }; THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); THREE.Bone.prototype.constructor = THREE.Bone; - // File:src/objects/Skeleton.js /** @@ -15397,7 +15734,7 @@ THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) { } else { - console.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); + THREE.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); this.boneInverses = []; @@ -15537,7 +15874,7 @@ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { var bone, gbone, p, q, s; - for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) { + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { gbone = this.geometry.bones[ b ]; @@ -15564,7 +15901,7 @@ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { } - for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) { + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { gbone = this.geometry.bones[ b ]; @@ -15660,7 +15997,7 @@ THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) { } else { - console.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode ); + THREE.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode ); } @@ -15755,7 +16092,6 @@ THREE.MorphAnimMesh.prototype.parseAnimations = function () { if ( parts && parts.length > 1 ) { var label = parts[ 1 ]; - var num = parts[ 2 ]; if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity }; @@ -15794,7 +16130,7 @@ THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { } else { - console.warn( 'animation[' + label + '] undefined' ); + THREE.warn( 'THREE.MorphAnimMesh: animation[' + label + '] undefined in .playAnimation()' ); } @@ -16123,7 +16459,7 @@ THREE.LensFlare = function ( texture, size, distance, blending, color ) { this.positionScreen = new THREE.Vector3(); this.customUpdateCallback = undefined; - if( texture !== undefined ) { + if ( texture !== undefined ) { this.add( texture, size, distance, blending, color ); @@ -16175,7 +16511,7 @@ THREE.LensFlare.prototype.updateLensFlares = function () { var vecX = - this.positionScreen.x * 2; var vecY = - this.positionScreen.y * 2; - for( f = 0; f < fl; f ++ ) { + for ( f = 0; f < fl; f ++ ) { flare = this.lensFlares[ f ]; @@ -16280,19 +16616,19 @@ THREE.ShaderChunk = {}; // File:src/renderers/shaders/ShaderChunk/common.glsl -THREE.ShaderChunk[ 'common'] = "#define PI 3.14159\n#define PI2 6.28318\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n\nfloat square( in float a ) { return a*a; }\nvec2 square( in vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }\nvec3 square( in vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }\nvec4 square( in vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }\nfloat saturate( in float a ) { return clamp( a, 0.0, 1.0 ); }\nvec2 saturate( in vec2 a ) { return clamp( a, 0.0, 1.0 ); }\nvec3 saturate( in vec3 a ) { return clamp( a, 0.0, 1.0 ); }\nvec4 saturate( in vec4 a ) { return clamp( a, 0.0, 1.0 ); }\nfloat average( in float a ) { return a; }\nfloat average( in vec2 a ) { return ( a.x + a.y) * 0.5; }\nfloat average( in vec3 a ) { return ( a.x + a.y + a.z) / 3.0; }\nfloat average( in vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }\nfloat whiteCompliment( in float a ) { return saturate( 1.0 - a ); }\nvec2 whiteCompliment( in vec2 a ) { return saturate( vec2(1.0) - a ); }\nvec3 whiteCompliment( in vec3 a ) { return saturate( vec3(1.0) - a ); }\nvec4 whiteCompliment( in vec4 a ) { return saturate( vec4(1.0) - a ); }\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n}\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {\n float distance = dot( planeNormal, point-pointOnPlane );\n return point - distance * planeNormal;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );\n}"; +THREE.ShaderChunk[ 'common'] = "#define PI 3.14159\n#define PI2 6.28318\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n\nfloat square( in float a ) { return a*a; }\nvec2 square( in vec2 a ) { return vec2( a.x*a.x, a.y*a.y ); }\nvec3 square( in vec3 a ) { return vec3( a.x*a.x, a.y*a.y, a.z*a.z ); }\nvec4 square( in vec4 a ) { return vec4( a.x*a.x, a.y*a.y, a.z*a.z, a.w*a.w ); }\nfloat saturate( in float a ) { return clamp( a, 0.0, 1.0 ); }\nvec2 saturate( in vec2 a ) { return clamp( a, 0.0, 1.0 ); }\nvec3 saturate( in vec3 a ) { return clamp( a, 0.0, 1.0 ); }\nvec4 saturate( in vec4 a ) { return clamp( a, 0.0, 1.0 ); }\nfloat average( in float a ) { return a; }\nfloat average( in vec2 a ) { return ( a.x + a.y) * 0.5; }\nfloat average( in vec3 a ) { return ( a.x + a.y + a.z) / 3.0; }\nfloat average( in vec4 a ) { return ( a.x + a.y + a.z + a.w) * 0.25; }\nfloat whiteCompliment( in float a ) { return saturate( 1.0 - a ); }\nvec2 whiteCompliment( in vec2 a ) { return saturate( vec2(1.0) - a ); }\nvec3 whiteCompliment( in vec3 a ) { return saturate( vec3(1.0) - a ); }\nvec4 whiteCompliment( in vec4 a ) { return saturate( vec4(1.0) - a ); }\nvec3 transformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );\n}\n// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\nvec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {\n return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal) {\n float distance = dot( planeNormal, point-pointOnPlane );\n return point - distance * planeNormal;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) );\n}\nfloat calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) {\n if ( decayExponent > 0.0 ) {\n return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );\n }\n return 1.0;\n}\n\nvec3 inputToLinear( in vec3 a ) {\n#ifdef GAMMA_INPUT\n return pow( a, vec3( float( GAMMA_FACTOR ) ) );\n#else\n return a;\n#endif\n}\nvec3 linearToOutput( in vec3 a ) {\n#ifdef GAMMA_OUTPUT\n return pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n#else\n return a;\n#endif\n}\n"; // File:src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl -THREE.ShaderChunk[ 'alphatest_fragment'] = "#ifdef ALPHATEST\n\n if ( gl_FragColor.a < ALPHATEST ) discard;\n\n#endif\n"; +THREE.ShaderChunk[ 'alphatest_fragment'] = "#ifdef ALPHATEST\n\n if ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl -THREE.ShaderChunk[ 'lights_lambert_vertex'] = "vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n vLightBack = vec3( 0.0 );\n\n#endif\n\ntransformedNormal = normalize( transformedNormal );\n\n#if MAX_DIR_LIGHTS > 0\n\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, dirVector );\n vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n\n #endif\n\n}\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float lDistance = 1.0;\n if ( pointLightDistance[ i ] > 0.0 )\n lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );\n\n lVector = normalize( lVector );\n float dotProduct = dot( transformedNormal, lVector );\n\n vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;\n\n #endif\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n float lDistance = 1.0;\n if ( spotLightDistance[ i ] > 0.0 )\n lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );\n\n lVector = normalize( lVector );\n\n float dotProduct = dot( transformedNormal, lVector );\n vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;\n\n #endif\n\n }\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, lVector );\n\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\n\n vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n\n #endif\n\n }\n\n#endif\n\nvLightFront = vLightFront * diffuse + diffuse * ambientLightColor + emissive;\n\n#ifdef DOUBLE_SIDED\n\n vLightBack = vLightBack * diffuse + diffuse * ambientLightColor + emissive;\n \n#endif"; +THREE.ShaderChunk[ 'lights_lambert_vertex'] = "vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n vLightBack = vec3( 0.0 );\n\n#endif\n\ntransformedNormal = normalize( transformedNormal );\n\n#if MAX_DIR_LIGHTS > 0\n\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, dirVector );\n vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n\n #endif\n\n}\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n lVector = normalize( lVector );\n float dotProduct = dot( transformedNormal, lVector );\n\n vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;\n\n #endif\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n float dotProduct = dot( transformedNormal, lVector );\n vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n #ifdef DOUBLE_SIDED\n\n vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n #endif\n\n #endif\n\n #ifdef WRAP_AROUND\n\n vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n\n #ifdef DOUBLE_SIDED\n\n spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n\n #endif\n\n #endif\n\n vLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;\n\n #endif\n\n }\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n float dotProduct = dot( transformedNormal, lVector );\n\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\n\n vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n #ifdef DOUBLE_SIDED\n\n vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n\n #endif\n\n }\n\n#endif\n\nvLightFront += ambientLightColor;\n\n#ifdef DOUBLE_SIDED\n\n vLightBack += ambientLightColor;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl -THREE.ShaderChunk[ 'map_particle_pars_fragment'] = "#ifdef USE_MAP\n\n uniform sampler2D map;\n\n#endif"; +THREE.ShaderChunk[ 'map_particle_pars_fragment'] = "#ifdef USE_MAP\n\n uniform vec4 offsetRepeat;\n uniform sampler2D map;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/default_vertex.glsl @@ -16316,7 +16652,7 @@ THREE.ShaderChunk[ 'lightmap_pars_vertex'] = "#ifdef USE_LIGHTMAP\n\n varying ve // File:src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl -THREE.ShaderChunk[ 'lights_phong_fragment'] = "vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\n\n#ifdef DOUBLE_SIDED\n\n normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n#endif\n\n#ifdef USE_NORMALMAP\n\n normal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n vec3 pointDiffuse = vec3( 0.0 );\n vec3 pointSpecular = vec3( 0.0 );\n\n for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float lDistance = 1.0;\n if ( pointLightDistance[ i ] > 0.0 )\n lDistance = saturate( 1.0 - ( length( lVector ) / pointLightDistance[ i ] ) );\n\n lVector = normalize( lVector );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float pointDiffuseWeightFull = max( dotProduct, 0.0 );\n float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float pointDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;\n\n // specular\n\n vec3 pointHalfVector = normalize( lVector + viewPosition );\n float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\n pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n vec3 spotDiffuse = vec3( 0.0 );\n vec3 spotSpecular = vec3( 0.0 );\n\n for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float lDistance = 1.0;\n if ( spotLightDistance[ i ] > 0.0 )\n lDistance = saturate( 1.0 - ( length( lVector ) / spotLightDistance[ i ] ) );\n\n lVector = normalize( lVector );\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float spotDiffuseWeightFull = max( dotProduct, 0.0 );\n float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float spotDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;\n\n // specular\n\n vec3 spotHalfVector = normalize( lVector + viewPosition );\n float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\n spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;\n\n }\n\n }\n\n#endif\n\n#if MAX_DIR_LIGHTS > 0\n\n vec3 dirDiffuse = vec3( 0.0 );\n vec3 dirSpecular = vec3( 0.0 );\n\n for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, dirVector );\n\n #ifdef WRAP_AROUND\n\n float dirDiffuseWeightFull = max( dotProduct, 0.0 );\n float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float dirDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;\n\n // specular\n\n vec3 dirHalfVector = normalize( dirVector + viewPosition );\n float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\n /*\n // fresnel term from skin shader\n const float F0 = 0.128;\n\n float base = 1.0 - dot( viewPosition, dirHalfVector );\n float exponential = pow( base, 5.0 );\n\n float fresnel = exponential + F0 * ( 1.0 - exponential );\n */\n\n /*\n // fresnel term from fresnel shader\n const float mFresnelBias = 0.08;\n const float mFresnelScale = 0.3;\n const float mFresnelPower = 5.0;\n\n float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\n */\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n // dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n vec3 hemiDiffuse = vec3( 0.0 );\n vec3 hemiSpecular = vec3( 0.0 );\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n hemiDiffuse += diffuse * hemiColor;\n\n // specular (sky light)\n\n vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n float hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\n // specular (ground light)\n\n vec3 lVectorGround = -lVector;\n\n vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n float hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\n float dotProductGround = dot( normal, lVectorGround );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\n }\n\n#endif\n\nvec3 totalDiffuse = vec3( 0.0 );\nvec3 totalSpecular = vec3( 0.0 );\n\n#if MAX_DIR_LIGHTS > 0\n\n totalDiffuse += dirDiffuse;\n totalSpecular += dirSpecular;\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n totalDiffuse += hemiDiffuse;\n totalSpecular += hemiSpecular;\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n totalDiffuse += pointDiffuse;\n totalSpecular += pointSpecular;\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n totalDiffuse += spotDiffuse;\n totalSpecular += spotSpecular;\n\n#endif\n\n#ifdef METAL\n\n gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * diffuse + totalSpecular );\n\n#else\n\n gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * diffuse ) + totalSpecular;\n\n#endif"; +THREE.ShaderChunk[ 'lights_phong_fragment'] = "#ifndef FLAT_SHADED\n\n vec3 normal = normalize( vNormal );\n\n #ifdef DOUBLE_SIDED\n\n normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n #endif\n\n#else\n\n vec3 fdx = dFdx( vViewPosition );\n vec3 fdy = dFdy( vViewPosition );\n vec3 normal = normalize( cross( fdx, fdy ) );\n\n#endif\n\nvec3 viewPosition = normalize( vViewPosition );\n\n#ifdef USE_NORMALMAP\n\n normal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n\n#endif\n\nvec3 totalDiffuseLight = vec3( 0.0 );\nvec3 totalSpecularLight = vec3( 0.0 );\n\n#if MAX_POINT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float pointDiffuseWeightFull = max( dotProduct, 0.0 );\n float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float pointDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;\n\n // specular\n\n vec3 pointHalfVector = normalize( lVector + viewPosition );\n float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;\n\n }\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n vec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n lVector = normalize( lVector );\n\n float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\n if ( spotEffect > spotLightAngleCos[ i ] ) {\n\n spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n\n #ifdef WRAP_AROUND\n\n float spotDiffuseWeightFull = max( dotProduct, 0.0 );\n float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float spotDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;\n\n // specular\n\n vec3 spotHalfVector = normalize( lVector + viewPosition );\n float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;\n\n }\n\n }\n\n#endif\n\n#if MAX_DIR_LIGHTS > 0\n\n for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, dirVector );\n\n #ifdef WRAP_AROUND\n\n float dirDiffuseWeightFull = max( dotProduct, 0.0 );\n float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n\n #else\n\n float dirDiffuseWeight = max( dotProduct, 0.0 );\n\n #endif\n\n totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;\n\n // specular\n\n vec3 dirHalfVector = normalize( dirVector + viewPosition );\n float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\n /*\n // fresnel term from skin shader\n const float F0 = 0.128;\n\n float base = 1.0 - dot( viewPosition, dirHalfVector );\n float exponential = pow( base, 5.0 );\n\n float fresnel = exponential + F0 * ( 1.0 - exponential );\n */\n\n /*\n // fresnel term from fresnel shader\n const float mFresnelBias = 0.08;\n const float mFresnelScale = 0.3;\n const float mFresnelPower = 5.0;\n\n float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\n */\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n // dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\n\n vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n totalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\n\n }\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n // diffuse\n\n float dotProduct = dot( normal, lVector );\n float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n totalDiffuseLight += hemiColor;\n\n // specular (sky light)\n\n vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n float hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\n // specular (ground light)\n\n vec3 lVectorGround = -lVector;\n\n vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n float hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\n float dotProductGround = dot( normal, lVectorGround );\n\n float specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n totalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\n }\n\n#endif\n\n#ifdef METAL\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;\n\n#else\n\n outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/fog_pars_fragment.glsl @@ -16336,7 +16672,7 @@ THREE.ShaderChunk[ 'logdepthbuf_fragment'] = "#if defined(USE_LOGDEPTHBUF) && de // File:src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl -THREE.ShaderChunk[ 'normalmap_pars_fragment'] = "#ifdef USE_NORMALMAP\n\n uniform sampler2D normalMap;\n uniform vec2 normalScale;\n\n // Per-Pixel Tangent Space Normal Mapping\n // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n vec3 q0 = dFdx( eye_pos.xyz );\n vec3 q1 = dFdy( eye_pos.xyz );\n vec2 st0 = dFdx( vUv.st );\n vec2 st1 = dFdy( vUv.st );\n\n vec3 S = normalize( q0 * st1.t - q1 * st0.t );\n vec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n vec3 N = normalize( surf_norm );\n\n vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n mapN.xy = normalScale * mapN.xy;\n mat3 tsn = mat3( S, T, N );\n return normalize( tsn * mapN );\n\n }\n\n#endif\n"; +THREE.ShaderChunk[ 'normalmap_pars_fragment'] = "#ifdef USE_NORMALMAP\n\n uniform sampler2D normalMap;\n uniform vec2 normalScale;\n\n // Per-Pixel Tangent Space Normal Mapping\n // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n vec3 q0 = dFdx( eye_pos.xyz );\n vec3 q1 = dFdy( eye_pos.xyz );\n vec2 st0 = dFdx( vUv.st );\n vec2 st1 = dFdy( vUv.st );\n\n vec3 S = normalize( q0 * st1.t - q1 * st0.t );\n vec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n vec3 N = normalize( surf_norm );\n\n vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n mapN.xy = normalScale * mapN.xy;\n mat3 tsn = mat3( S, T, N );\n return normalize( tsn * mapN );\n\n }\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/lights_phong_pars_vertex.glsl @@ -16356,7 +16692,7 @@ THREE.ShaderChunk[ 'lights_phong_vertex'] = "#if MAX_SPOT_LIGHTS > 0 || defined( // File:src/renderers/shaders/ShaderChunk/map_fragment.glsl -THREE.ShaderChunk[ 'map_fragment'] = "#ifdef USE_MAP\n\n vec4 texelColor = texture2D( map, vUv );\n\n #ifdef GAMMA_INPUT\n\n texelColor.xyz *= texelColor.xyz;\n\n #endif\n\n gl_FragColor = gl_FragColor * texelColor;\n\n#endif"; +THREE.ShaderChunk[ 'map_fragment'] = "#ifdef USE_MAP\n\n vec4 texelColor = texture2D( map, vUv );\n\n texelColor.xyz = inputToLinear( texelColor.xyz );\n\n diffuseColor *= texelColor;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/lightmap_vertex.glsl @@ -16364,7 +16700,7 @@ THREE.ShaderChunk[ 'lightmap_vertex'] = "#ifdef USE_LIGHTMAP\n\n vUv2 = uv2;\n\n // File:src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl -THREE.ShaderChunk[ 'map_particle_fragment'] = "#ifdef USE_MAP\n\n gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );\n\n#endif"; +THREE.ShaderChunk[ 'map_particle_fragment'] = "#ifdef USE_MAP\n\n diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/color_pars_fragment.glsl @@ -16372,7 +16708,7 @@ THREE.ShaderChunk[ 'color_pars_fragment'] = "#ifdef USE_COLOR\n\n varying vec3 v // File:src/renderers/shaders/ShaderChunk/color_vertex.glsl -THREE.ShaderChunk[ 'color_vertex'] = "#ifdef USE_COLOR\n\n #ifdef GAMMA_INPUT\n\n vColor = square( color );\n\n #else\n\n vColor = color;\n\n #endif\n\n#endif"; +THREE.ShaderChunk[ 'color_vertex'] = "#ifdef USE_COLOR\n\n vColor.xyz = inputToLinear( color.xyz );\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/skinning_vertex.glsl @@ -16384,7 +16720,7 @@ THREE.ShaderChunk[ 'envmap_pars_vertex'] = "#if defined( USE_ENVMAP ) && ! defin // File:src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl -THREE.ShaderChunk[ 'linear_to_gamma_fragment'] = "#ifdef GAMMA_OUTPUT\n\n gl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n\n#endif"; +THREE.ShaderChunk[ 'linear_to_gamma_fragment'] = "\n outgoingLight = linearToOutput( outgoingLight );\n"; // File:src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl @@ -16392,7 +16728,7 @@ THREE.ShaderChunk[ 'color_pars_vertex'] = "#ifdef USE_COLOR\n\n varying vec3 vCo // File:src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl -THREE.ShaderChunk[ 'lights_lambert_pars_vertex'] = "uniform vec3 diffuse;\nuniform vec3 emissive;\n\nuniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n"; +THREE.ShaderChunk[ 'lights_lambert_pars_vertex'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/map_pars_vertex.glsl @@ -16400,7 +16736,7 @@ THREE.ShaderChunk[ 'map_pars_vertex'] = "#if defined( USE_MAP ) || defined( USE_ // File:src/renderers/shaders/ShaderChunk/envmap_fragment.glsl -THREE.ShaderChunk[ 'envmap_fragment'] = "#ifdef USE_ENVMAP\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n // Transforming Normal Vectors with the Inverse Transformation\n vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n #ifdef ENVMAP_MODE_REFLECTION\n\n vec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n #else\n\n vec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n #endif\n\n #else\n\n vec3 reflectVec = vReflect;\n\n #endif\n\n #ifdef DOUBLE_SIDED\n float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n #else\n float flipNormal = 1.0;\n #endif\n\n #ifdef ENVMAP_TYPE_CUBE\n vec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #elif defined( ENVMAP_TYPE_EQUIREC )\n vec2 sampleUV;\n sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n vec4 envColor = texture2D( envMap, sampleUV );\n \n #elif defined( ENVMAP_TYPE_SPHERE )\n vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n #endif\n\n #ifdef GAMMA_INPUT\n\n envColor.xyz *= envColor.xyz;\n\n #endif\n\n #ifdef ENVMAP_BLENDING_MULTIPLY\n\n gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_MIX )\n\n gl_FragColor.xyz = mix( gl_FragColor.xyz, envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_ADD )\n\n gl_FragColor.xyz += envColor.xyz * specularStrength * reflectivity;\n\n #endif\n\n#endif\n"; +THREE.ShaderChunk[ 'envmap_fragment'] = "#ifdef USE_ENVMAP\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n // Transforming Normal Vectors with the Inverse Transformation\n vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n #ifdef ENVMAP_MODE_REFLECTION\n\n vec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n #else\n\n vec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n #endif\n\n #else\n\n vec3 reflectVec = vReflect;\n\n #endif\n\n #ifdef DOUBLE_SIDED\n float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n #else\n float flipNormal = 1.0;\n #endif\n\n #ifdef ENVMAP_TYPE_CUBE\n vec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #elif defined( ENVMAP_TYPE_EQUIREC )\n vec2 sampleUV;\n sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n vec4 envColor = texture2D( envMap, sampleUV );\n\n #elif defined( ENVMAP_TYPE_SPHERE )\n vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n #endif\n\n envColor.xyz = inputToLinear( envColor.xyz );\n\n #ifdef ENVMAP_BLENDING_MULTIPLY\n\n outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_MIX )\n\n outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\n #elif defined( ENVMAP_BLENDING_ADD )\n\n outgoingLight += envColor.xyz * specularStrength * reflectivity;\n\n #endif\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl @@ -16420,11 +16756,11 @@ THREE.ShaderChunk[ 'specularmap_fragment'] = "float specularStrength;\n\n#ifdef // File:src/renderers/shaders/ShaderChunk/fog_fragment.glsl -THREE.ShaderChunk[ 'fog_fragment'] = "#ifdef USE_FOG\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n float depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n #else\n\n float depth = gl_FragCoord.z / gl_FragCoord.w;\n\n #endif\n\n #ifdef FOG_EXP2\n\n float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n fogFactor = whiteCompliment( fogFactor );\n\n #else\n\n float fogFactor = smoothstep( fogNear, fogFar, depth );\n\n #endif\n \n gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n\n#endif"; +THREE.ShaderChunk[ 'fog_fragment'] = "#ifdef USE_FOG\n\n #ifdef USE_LOGDEPTHBUF_EXT\n\n float depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n #else\n\n float depth = gl_FragCoord.z / gl_FragCoord.w;\n\n #endif\n\n #ifdef FOG_EXP2\n\n float fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n fogFactor = whiteCompliment( fogFactor );\n\n #else\n\n float fogFactor = smoothstep( fogNear, fogFar, depth );\n\n #endif\n \n outgoingLight = mix( outgoingLight, fogColor, fogFactor );\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl -THREE.ShaderChunk[ 'bumpmap_pars_fragment'] = "#ifdef USE_BUMPMAP\n\n uniform sampler2D bumpMap;\n uniform float bumpScale;\n\n // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n vec2 dHdxy_fwd() {\n\n vec2 dSTdx = dFdx( vUv );\n vec2 dSTdy = dFdy( vUv );\n\n float Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n return vec2( dBx, dBy );\n\n }\n\n vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n vec3 vSigmaX = dFdx( surf_pos );\n vec3 vSigmaY = dFdy( surf_pos );\n vec3 vN = surf_norm; // normalized\n\n vec3 R1 = cross( vSigmaY, vN );\n vec3 R2 = cross( vN, vSigmaX );\n\n float fDet = dot( vSigmaX, R1 );\n\n vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n return normalize( abs( fDet ) * surf_norm - vGrad );\n\n }\n\n#endif"; +THREE.ShaderChunk[ 'bumpmap_pars_fragment'] = "#ifdef USE_BUMPMAP\n\n uniform sampler2D bumpMap;\n uniform float bumpScale;\n\n // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n vec2 dHdxy_fwd() {\n\n vec2 dSTdx = dFdx( vUv );\n vec2 dSTdy = dFdy( vUv );\n\n float Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n return vec2( dBx, dBy );\n\n }\n\n vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n vec3 vSigmaX = dFdx( surf_pos );\n vec3 vSigmaY = dFdy( surf_pos );\n vec3 vN = surf_norm; // normalized\n\n vec3 R1 = cross( vSigmaY, vN );\n vec3 R2 = cross( vN, vSigmaX );\n\n float fDet = dot( vSigmaX, R1 );\n\n vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n return normalize( abs( fDet ) * surf_norm - vGrad );\n\n }\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl @@ -16432,7 +16768,7 @@ THREE.ShaderChunk[ 'defaultnormal_vertex'] = "#ifdef USE_SKINNING\n\n vec3 objec // File:src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl -THREE.ShaderChunk[ 'lights_phong_pars_fragment'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;"; +THREE.ShaderChunk[ 'lights_phong_pars_fragment'] = "uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n uniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n uniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n uniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n varying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n uniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n varying vec3 vNormal;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/skinbase_vertex.glsl @@ -16444,7 +16780,7 @@ THREE.ShaderChunk[ 'map_vertex'] = "#if defined( USE_MAP ) || defined( USE_BUMPM // File:src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl -THREE.ShaderChunk[ 'lightmap_fragment'] = "#ifdef USE_LIGHTMAP\n\n gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );\n\n#endif"; +THREE.ShaderChunk[ 'lightmap_fragment'] = "#ifdef USE_LIGHTMAP\n\n outgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl @@ -16452,7 +16788,7 @@ THREE.ShaderChunk[ 'shadowmap_pars_vertex'] = "#ifdef USE_SHADOWMAP\n\n varying // File:src/renderers/shaders/ShaderChunk/color_fragment.glsl -THREE.ShaderChunk[ 'color_fragment'] = "#ifdef USE_COLOR\n\n gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );\n\n#endif"; +THREE.ShaderChunk[ 'color_fragment'] = "#ifdef USE_COLOR\n\n diffuseColor.rgb *= vColor;\n\n#endif"; // File:src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl @@ -16464,7 +16800,7 @@ THREE.ShaderChunk[ 'envmap_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( U // File:src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl -THREE.ShaderChunk[ 'shadowmap_fragment'] = "#ifdef USE_SHADOWMAP\n\n #ifdef SHADOWMAP_DEBUG\n\n vec3 frustumColors[3];\n frustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n frustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n frustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n #endif\n\n #ifdef SHADOWMAP_CASCADE\n\n int inFrustumCount = 0;\n\n #endif\n\n float fDepth;\n vec3 shadowColor = vec3( 1.0 );\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n // if ( something && something ) breaks ATI OpenGL shader compiler\n // if ( all( something, something ) ) using this instead\n\n bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n bool inFrustum = all( inFrustumVec );\n\n // don't shadow pixels outside of light frustum\n // use just first frustum (for cascades)\n // don't shadow pixels behind far plane of light frustum\n\n #ifdef SHADOWMAP_CASCADE\n\n inFrustumCount += int( inFrustum );\n bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n #else\n\n bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n #endif\n\n bool frustumTest = all( frustumTestVec );\n\n if ( frustumTest ) {\n\n shadowCoord.z += shadowBias[ i ];\n\n #if defined( SHADOWMAP_TYPE_PCF )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n /*\n // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n // must enroll loop manually\n\n for ( float y = -1.25; y <= 1.25; y += 1.25 )\n for ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n // doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n //vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n shadow += 1.0;\n\n }\n\n shadow /= 9.0;\n\n */\n\n const float shadowDelta = 1.0 / 9.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.25 * xPixelOffset;\n float dy0 = -1.25 * yPixelOffset;\n float dx1 = 1.25 * xPixelOffset;\n float dy1 = 1.25 * yPixelOffset;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.0 * xPixelOffset;\n float dy0 = -1.0 * yPixelOffset;\n float dx1 = 1.0 * xPixelOffset;\n float dy1 = 1.0 * yPixelOffset;\n\n mat3 shadowKernel;\n mat3 depthKernel;\n\n depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n vec3 shadowZ = vec3( shadowCoord.z );\n shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n shadowKernel[0] *= vec3(0.25);\n\n shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n shadowKernel[1] *= vec3(0.25);\n\n shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n shadowKernel[2] *= vec3(0.25);\n\n vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n vec4 shadowValues;\n shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n shadow = dot( shadowValues, vec4( 1.0 ) );\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #else\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n\n // spot with multiple shadows is darker\n\n shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n // spot with multiple shadows has the same color as single shadow spot\n\n // shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n #endif\n\n }\n\n\n #ifdef SHADOWMAP_DEBUG\n\n #ifdef SHADOWMAP_CASCADE\n\n if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n\n #else\n\n if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n\n #endif\n\n #endif\n\n }\n\n #ifdef GAMMA_OUTPUT\n\n shadowColor *= shadowColor;\n\n #endif\n\n gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n\n#endif\n"; +THREE.ShaderChunk[ 'shadowmap_fragment'] = "#ifdef USE_SHADOWMAP\n\n #ifdef SHADOWMAP_DEBUG\n\n vec3 frustumColors[3];\n frustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n frustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n frustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n #endif\n\n #ifdef SHADOWMAP_CASCADE\n\n int inFrustumCount = 0;\n\n #endif\n\n float fDepth;\n vec3 shadowColor = vec3( 1.0 );\n\n for( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n // if ( something && something ) breaks ATI OpenGL shader compiler\n // if ( all( something, something ) ) using this instead\n\n bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n bool inFrustum = all( inFrustumVec );\n\n // don't shadow pixels outside of light frustum\n // use just first frustum (for cascades)\n // don't shadow pixels behind far plane of light frustum\n\n #ifdef SHADOWMAP_CASCADE\n\n inFrustumCount += int( inFrustum );\n bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n #else\n\n bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n #endif\n\n bool frustumTest = all( frustumTestVec );\n\n if ( frustumTest ) {\n\n shadowCoord.z += shadowBias[ i ];\n\n #if defined( SHADOWMAP_TYPE_PCF )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n /*\n // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n // must enroll loop manually\n\n for ( float y = -1.25; y <= 1.25; y += 1.25 )\n for ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n // doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n //vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n shadow += 1.0;\n\n }\n\n shadow /= 9.0;\n\n */\n\n const float shadowDelta = 1.0 / 9.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.25 * xPixelOffset;\n float dy0 = -1.25 * yPixelOffset;\n float dx1 = 1.25 * xPixelOffset;\n float dy1 = 1.25 * yPixelOffset;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n if ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n // Percentage-close filtering\n // (9 pixel kernel)\n // http://fabiensanglard.net/shadowmappingPCF/\n\n float shadow = 0.0;\n\n float xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n float yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n float dx0 = -1.0 * xPixelOffset;\n float dy0 = -1.0 * yPixelOffset;\n float dx1 = 1.0 * xPixelOffset;\n float dy1 = 1.0 * yPixelOffset;\n\n mat3 shadowKernel;\n mat3 depthKernel;\n\n depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n vec3 shadowZ = vec3( shadowCoord.z );\n shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n shadowKernel[0] *= vec3(0.25);\n\n shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n shadowKernel[1] *= vec3(0.25);\n\n shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n shadowKernel[2] *= vec3(0.25);\n\n vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n vec4 shadowValues;\n shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n shadow = dot( shadowValues, vec4( 1.0 ) );\n\n shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n #else\n\n vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n float fDepth = unpackDepth( rgbaDepth );\n\n if ( fDepth < shadowCoord.z )\n\n // spot with multiple shadows is darker\n\n shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n // spot with multiple shadows has the same color as single shadow spot\n\n // shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n #endif\n\n }\n\n\n #ifdef SHADOWMAP_DEBUG\n\n #ifdef SHADOWMAP_CASCADE\n\n if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];\n\n #else\n\n if ( inFrustum ) outgoingLight *= frustumColors[ i ];\n\n #endif\n\n #endif\n\n }\n\n // NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014\n shadowColor = inputToLinear( shadowColor );\n\n outgoingLight = outgoingLight * shadowColor;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl @@ -16484,7 +16820,7 @@ THREE.ShaderChunk[ 'logdepthbuf_pars_fragment'] = "#ifdef USE_LOGDEPTHBUF\n\n un // File:src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl -THREE.ShaderChunk[ 'alphamap_fragment'] = "#ifdef USE_ALPHAMAP\n\n gl_FragColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n"; +THREE.ShaderChunk[ 'alphamap_fragment'] = "#ifdef USE_ALPHAMAP\n\n diffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n"; // File:src/renderers/shaders/ShaderChunk/alphamap_pars_fragment.glsl @@ -16624,13 +16960,15 @@ THREE.UniformsLib = { "pointLightColor" : { type: "fv", value: [] }, "pointLightPosition" : { type: "fv", value: [] }, "pointLightDistance" : { type: "fv1", value: [] }, + "pointLightDecay" : { type: "fv1", value: [] }, "spotLightColor" : { type: "fv", value: [] }, "spotLightPosition" : { type: "fv", value: [] }, "spotLightDirection" : { type: "fv", value: [] }, "spotLightDistance" : { type: "fv1", value: [] }, "spotLightAngleCos" : { type: "fv1", value: [] }, - "spotLightExponent" : { type: "fv1", value: [] } + "spotLightExponent" : { type: "fv1", value: [] }, + "spotLightDecay" : { type: "fv1", value: [] } }, @@ -16641,6 +16979,7 @@ THREE.UniformsLib = { "size" : { type: "f", value: 1.0 }, "scale" : { type: "f", value: 1.0 }, "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, "fogDensity" : { type: "f", value: 0.00025 }, "fogNear" : { type: "f", value: 1 }, @@ -16744,22 +17083,28 @@ THREE.ShaderLib = { "void main() {", - " gl_FragColor = vec4( diffuse, opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], + + " outgoingLight = diffuseColor.rgb;", // simple shader + + THREE.ShaderChunk[ "lightmap_fragment" ], // TODO: Light map on an otherwise unlit surface doesn't make sense. THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], // TODO: Shadows on an otherwise unlit surface doesn't make sense. THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -16832,6 +17177,8 @@ THREE.ShaderLib = { fragmentShader: [ + "uniform vec3 diffuse;", + "uniform vec3 emissive;", "uniform float opacity;", "varying vec3 vLightFront;", @@ -16855,10 +17202,12 @@ THREE.ShaderLib = { "void main() {", - " gl_FragColor = vec4( vec3( 1.0 ), opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], @@ -16869,18 +17218,17 @@ THREE.ShaderLib = { //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", " if ( gl_FrontFacing )", - " gl_FragColor.xyz *= vLightFront;", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", " else", - " gl_FragColor.xyz *= vLightBack;", + " outgoingLight += diffuseColor.rgb * vLightBack + emissive;", " #else", - " gl_FragColor.xyz *= vLightFront;", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", " #endif", THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], @@ -16888,6 +17236,8 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -16919,7 +17269,12 @@ THREE.ShaderLib = { "#define PHONG", "varying vec3 vViewPosition;", - "varying vec3 vNormal;", + + "#ifndef FLAT_SHADED", + + " varying vec3 vNormal;", + + "#endif", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "map_pars_vertex" ], @@ -16943,8 +17298,12 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], + "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED + " vNormal = normalize( transformedNormal );", + "#endif", + THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "default_vertex" ], @@ -16966,11 +17325,10 @@ THREE.ShaderLib = { "#define PHONG", "uniform vec3 diffuse;", - "uniform float opacity;", - "uniform vec3 emissive;", "uniform vec3 specular;", "uniform float shininess;", + "uniform float opacity;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], @@ -16988,10 +17346,12 @@ THREE.ShaderLib = { "void main() {", - " gl_FragColor = vec4( vec3( 1.0 ), opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], @@ -16999,7 +17359,6 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "lights_phong_fragment" ], THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], @@ -17007,6 +17366,8 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -17068,15 +17429,21 @@ THREE.ShaderLib = { "void main() {", - " gl_FragColor = vec4( psColor, opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( psColor, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_particle_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + + " outgoingLight = diffuseColor.rgb;", // simple shader + THREE.ShaderChunk[ "shadowmap_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -17147,12 +17514,18 @@ THREE.ShaderLib = { " }", - " gl_FragColor = vec4( diffuse, opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "color_fragment" ], + + " outgoingLight = diffuseColor.rgb;", // simple shader + THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -17209,7 +17582,7 @@ THREE.ShaderLib = { " #endif", " float color = 1.0 - smoothstep( mNear, mFar, depth );", - " gl_FragColor = vec4( vec3( color ), opacity );", + " gl_FragColor = vec4( vec3( color ), opacity );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects "}" @@ -17359,7 +17732,7 @@ THREE.ShaderLib = { "vec3 direction = normalize( vWorldPosition );", "vec2 sampleUV;", "sampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );", - "sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;", + "sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;", "gl_FragColor = texture2D( tEquirect, sampleUV );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], @@ -17509,6 +17882,7 @@ THREE.WebGLRenderer = function ( parameters ) { // physically based shading + this.gammaFactor = 2.0; // for backwards compatibility this.gammaInput = false; this.gammaOutput = false; @@ -17568,29 +17942,6 @@ THREE.WebGLRenderer = function ( parameters ) { _usedTextureUnits = 0, - // GL state cache - - _oldDoubleSided = - 1, - _oldFlipSided = - 1, - - _oldBlending = - 1, - - _oldBlendEquation = - 1, - _oldBlendSrc = - 1, - _oldBlendDst = - 1, - _oldBlendEquationAlpha = - 1, - _oldBlendSrcAlpha = - 1, - _oldBlendDstAlpha = - 1, - - _oldDepthTest = - 1, - _oldDepthWrite = - 1, - - _oldPolygonOffset = null, - _oldPolygonOffsetFactor = null, - _oldPolygonOffsetUnits = null, - - _oldLineWidth = null, - _viewportX = 0, _viewportY = 0, _viewportWidth = _canvas.width, @@ -17598,9 +17949,6 @@ THREE.WebGLRenderer = function ( parameters ) { _currentWidth = 0, _currentHeight = 0, - _newAttributes = new Uint8Array( 16 ), - _enabledAttributes = new Uint8Array( 16 ), - // frustum _frustum = new THREE.Frustum(), @@ -17608,7 +17956,6 @@ THREE.WebGLRenderer = function ( parameters ) { // camera matrices cache _projScreenMatrix = new THREE.Matrix4(), - _projScreenMatrixPS = new THREE.Matrix4(), _vector3 = new THREE.Vector3(), @@ -17622,8 +17969,8 @@ THREE.WebGLRenderer = function ( parameters ) { ambient: [ 0, 0, 0 ], directional: { length: 0, colors:[], positions: [] }, - point: { length: 0, colors: [], positions: [], distances: [] }, - spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [] }, + point: { length: 0, colors: [], positions: [], distances: [], decays: [] }, + spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] }, hemi: { length: 0, skyColors: [], groundColors: [], positions: [] } }; @@ -17672,10 +18019,12 @@ THREE.WebGLRenderer = function ( parameters ) { } catch ( error ) { - console.error( error ); + THREE.error( 'THREE.WebGLRenderer: ' + error ); } + var state = new THREE.WebGLState( _gl, paramThreeToGL ); + if ( _gl.getShaderPrecisionFormat === undefined ) { _gl.getShaderPrecisionFormat = function () { @@ -17694,6 +18043,8 @@ THREE.WebGLRenderer = function ( parameters ) { extensions.get( 'OES_texture_float' ); extensions.get( 'OES_texture_float_linear' ); + extensions.get( 'OES_texture_half_float' ); + extensions.get( 'OES_texture_half_float_linear' ); extensions.get( 'OES_standard_derivatives' ); if ( _logarithmicDepthBuffer ) { @@ -17704,6 +18055,18 @@ THREE.WebGLRenderer = function ( parameters ) { // + var glClearColor = function ( r, g, b, a ) { + + if ( _premultipliedAlpha === true ) { + + r *= a; g *= a; b *= a; + + } + + _gl.clearColor( r, g, b, a ); + + }; + var setDefaultGLState = function () { _gl.clearColor( 0, 0, 0, 1 ); @@ -17723,7 +18086,7 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; @@ -17732,27 +18095,19 @@ THREE.WebGLRenderer = function ( parameters ) { _currentProgram = null; _currentCamera = null; - _oldBlending = - 1; - _oldDepthTest = - 1; - _oldDepthWrite = - 1; - _oldDoubleSided = - 1; - _oldFlipSided = - 1; _currentGeometryProgram = ''; _currentMaterialId = - 1; _lightsNeedUpdate = true; - for ( var i = 0; i < _enabledAttributes.length; i ++ ) { - - _enabledAttributes[ i ] = 0; - - } + state.reset(); }; setDefaultGLState(); this.context = _gl; + this.state = state; // GPU capabilities @@ -17768,11 +18123,9 @@ THREE.WebGLRenderer = function ( parameters ) { 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 getCompressedTextureFormats = ( function () { @@ -17792,7 +18145,7 @@ THREE.WebGLRenderer = function ( parameters ) { var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ); - for ( var i = 0; i < formats.length; i ++ ){ + for ( var i = 0; i < formats.length; i ++ ) { array.push( formats[ i ] ); @@ -17816,12 +18169,12 @@ THREE.WebGLRenderer = function ( parameters ) { if ( mediumpAvailable ) { _precision = 'mediump'; - console.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' ); + THREE.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' ); } else { _precision = 'lowp'; - console.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' ); + THREE.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' ); } @@ -17830,7 +18183,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( _precision === 'mediump' && ! mediumpAvailable ) { _precision = 'lowp'; - console.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' ); + THREE.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' ); } @@ -17867,6 +18220,12 @@ THREE.WebGLRenderer = function ( parameters ) { }; + this.supportsHalfFloatTextures = function () { + + return extensions.get( 'OES_texture_half_float' ); + + }; + this.supportsStandardDerivatives = function () { return extensions.get( 'OES_standard_derivatives' ); @@ -17987,9 +18346,10 @@ THREE.WebGLRenderer = function ( parameters ) { this.setClearColor = function ( color, alpha ) { _clearColor.set( color ); + _clearAlpha = alpha !== undefined ? alpha : 1; - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; @@ -18003,7 +18363,7 @@ THREE.WebGLRenderer = function ( parameters ) { _clearAlpha = alpha; - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; @@ -18481,8 +18841,6 @@ THREE.WebGLRenderer = function ( parameters ) { geometry.__vertexArray = new Float32Array( nvertices * 3 ); geometry.__colorArray = new Float32Array( nvertices * 3 ); - geometry.__sortArray = []; - geometry.__webglParticleCount = nvertices; initCustomAttributes( object ); @@ -18640,19 +18998,19 @@ THREE.WebGLRenderer = function ( parameters ) { ? object.material.materials[ geometryGroup.materialIndex ] : object.material; - }; + } - function materialNeedsSmoothNormals ( material ) { + function materialNeedsFaceNormals ( material ) { - return material && material.shading !== undefined && material.shading === THREE.SmoothShading; + return material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading; - }; + } // Buffer setting function setParticleBuffers ( geometry, hint, object ) { - var v, c, vertex, offset, index, color, + var v, c, vertex, offset, color, vertices = geometry.vertices, vl = vertices.length, @@ -18663,15 +19021,12 @@ THREE.WebGLRenderer = function ( parameters ) { 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, + ca, cal, value, customAttribute; if ( dirtyVertices ) { @@ -18830,7 +19185,7 @@ THREE.WebGLRenderer = function ( parameters ) { customAttributes = geometry.__webglCustomAttributesList, i, il, - a, ca, cal, value, + ca, cal, value, customAttribute; if ( dirtyVertices ) { @@ -18987,23 +19342,20 @@ THREE.WebGLRenderer = function ( parameters ) { } - var needsSmoothNormals = materialNeedsSmoothNormals( material ); + var needsFaceNormals = materialNeedsFaceNormals( material ); var f, fl, fi, face, - vertexNormals, faceNormal, normal, + vertexNormals, faceNormal, vertexColors, faceColor, vertexTangents, - uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, + uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3, c1, c2, c3, - sw1, sw2, sw3, sw4, - si1, si2, si3, si4, - sa1, sa2, sa3, sa4, - sb1, sb2, sb3, sb4, - m, ml, i, il, + sw1, sw2, sw3, + si1, si2, si3, + i, il, vn, uvi, uv2i, vk, vkl, vka, nka, chf, faceVertexNormals, - a, vertexIndex = 0, @@ -19018,7 +19370,6 @@ THREE.WebGLRenderer = function ( parameters ) { offset_skin = 0, offset_morphTarget = 0, offset_custom = 0, - offset_customSrc = 0, value, @@ -19058,8 +19409,6 @@ THREE.WebGLRenderer = function ( parameters ) { obj_uvs = geometry.faceVertexUvs[ 0 ], obj_uvs2 = geometry.faceVertexUvs[ 1 ], - obj_colors = geometry.colors, - obj_skinIndices = geometry.skinIndices, obj_skinWeights = geometry.skinWeights, @@ -19132,7 +19481,13 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material.morphNormals ) { - if ( needsSmoothNormals ) { + if ( needsFaceNormals ) { + + n1 = morphNormals[ vk ].faceNormals[ chf ]; + n2 = n1; + n3 = n1; + + } else { faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; @@ -19140,12 +19495,6 @@ THREE.WebGLRenderer = function ( parameters ) { n2 = faceVertexNormals.b; n3 = faceVertexNormals.c; - } else { - - n1 = morphNormals[ vk ].faceNormals[ chf ]; - n2 = n1; - n3 = n1; - } nka = morphNormalsArrays[ vk ]; @@ -19341,7 +19690,7 @@ THREE.WebGLRenderer = function ( parameters ) { vertexNormals = face.vertexNormals; faceNormal = face.normal; - if ( vertexNormals.length === 3 && needsSmoothNormals ) { + if ( vertexNormals.length === 3 && needsFaceNormals === false ) { for ( i = 0; i < 3; i ++ ) { @@ -19482,7 +19831,6 @@ THREE.WebGLRenderer = function ( parameters ) { if ( ! customAttribute.__original.needsUpdate ) continue; offset_custom = 0; - offset_customSrc = 0; if ( customAttribute.size === 1 ) { @@ -19782,7 +20130,7 @@ THREE.WebGLRenderer = function ( parameters ) { this.renderBufferImmediate = function ( object, program, material ) { - initAttributes(); + state.initAttributes(); if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); @@ -19793,7 +20141,9 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.position ); + + state.enableAttribute( program.attributes.position ); + _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } @@ -19802,7 +20152,8 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); - if ( material.shading === THREE.FlatShading ) { + if ( material instanceof THREE.MeshPhongMaterial === false && + material.shading === THREE.FlatShading ) { var nx, ny, nz, nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, @@ -19846,7 +20197,9 @@ THREE.WebGLRenderer = function ( parameters ) { } _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.normal ); + + state.enableAttribute( program.attributes.normal ); + _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } @@ -19855,7 +20208,9 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.uv ); + + state.enableAttribute( program.attributes.uv ); + _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); } @@ -19864,12 +20219,14 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.color ); + + state.enableAttribute( program.attributes.color ); + _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); } - disableUnusedAttributes(); + state.disableUnusedAttributes(); _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); @@ -19899,7 +20256,7 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer ); - enableAttribute( programAttribute ); + state.enableAttribute( programAttribute ); _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32 @@ -19921,7 +20278,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - disableUnusedAttributes(); + state.disableUnusedAttributes(); } @@ -19946,7 +20303,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( updateBuffers ) { - initAttributes(); + state.initAttributes(); } @@ -20038,11 +20395,11 @@ THREE.WebGLRenderer = function ( parameters ) { // render non-indexed triangles - _gl.drawArrays( mode, 0, position.array.length / 3 ); + _gl.drawArrays( mode, 0, position.array.length / position.itemSize ); _this.info.render.calls ++; - _this.info.render.vertices += position.array.length / 3; - _this.info.render.faces += position.array.length / 9; + _this.info.render.vertices += position.array.length / position.itemSize; + _this.info.render.faces += position.array.length / ( 3 * position.itemSize ); } @@ -20157,7 +20514,7 @@ THREE.WebGLRenderer = function ( parameters ) { var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - setLineWidth( material.linewidth ); + state.setLineWidth( material.linewidth * pixelRatio ); var index = geometry.attributes.index; @@ -20287,7 +20644,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( updateBuffers ) { - initAttributes(); + state.initAttributes(); } @@ -20298,7 +20655,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( updateBuffers ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - enableAttribute( attributes.position ); + + state.enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20329,7 +20688,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); - enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); + + state.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); + _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); } @@ -20346,7 +20707,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - enableAttribute( attributes.color ); + + state.enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues !== undefined ) { @@ -20363,7 +20726,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes.normal >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - enableAttribute( attributes.normal ); + + state.enableAttribute( attributes.normal ); + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20373,7 +20738,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes.tangent >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - enableAttribute( attributes.tangent ); + + state.enableAttribute( attributes.tangent ); + _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); } @@ -20385,7 +20752,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object.geometry.faceVertexUvs[ 0 ] ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - enableAttribute( attributes.uv ); + + state.enableAttribute( attributes.uv ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues !== undefined ) { @@ -20402,7 +20771,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object.geometry.faceVertexUvs[ 1 ] ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - enableAttribute( attributes.uv2 ); + + state.enableAttribute( attributes.uv2 ); + _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues !== undefined ) { @@ -20418,11 +20789,15 @@ THREE.WebGLRenderer = function ( parameters ) { attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - enableAttribute( attributes.skinIndex ); + + state.enableAttribute( attributes.skinIndex ); + _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - enableAttribute( attributes.skinWeight ); + + state.enableAttribute( attributes.skinWeight ); + _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); } @@ -20432,14 +20807,16 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes.lineDistance >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); - enableAttribute( attributes.lineDistance ); + + state.enableAttribute( attributes.lineDistance ); + _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); } } - disableUnusedAttributes(); + state.disableUnusedAttributes(); // render mesh @@ -20451,7 +20828,8 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material.wireframe ) { - setLineWidth( material.wireframeLinewidth ); + state.setLineWidth( material.wireframeLinewidth * pixelRatio ); + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 ); @@ -20474,7 +20852,7 @@ THREE.WebGLRenderer = function ( parameters ) { var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - setLineWidth( material.linewidth ); + state.setLineWidth( material.linewidth * pixelRatio ); _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount ); @@ -20493,44 +20871,6 @@ THREE.WebGLRenderer = function ( parameters ) { }; - function initAttributes() { - - for ( var i = 0, l = _newAttributes.length; i < l; i ++ ) { - - _newAttributes[ i ] = 0; - - } - - } - - function enableAttribute( attribute ) { - - _newAttributes[ attribute ] = 1; - - if ( _enabledAttributes[ attribute ] === 0 ) { - - _gl.enableVertexAttribArray( attribute ); - _enabledAttributes[ attribute ] = 1; - - } - - } - - function disableUnusedAttributes() { - - for ( var i = 0, l = _enabledAttributes.length; i < l; i ++ ) { - - if ( _enabledAttributes[ i ] !== _newAttributes[ i ] ) { - - _gl.disableVertexAttribArray( i ); - _enabledAttributes[ i ] = 0; - - } - - } - - } - function setupMorphTargets ( material, geometryGroup, object ) { // set base @@ -20540,13 +20880,17 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); - enableAttribute( attributes.position ); + + state.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 ); + + state.enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20568,7 +20912,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attribute >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); - enableAttribute( attribute ); + + state.enableAttribute( attribute ); + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20578,7 +20924,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attribute >= 0 && material.morphNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); - enableAttribute( attribute ); + + state.enableAttribute( attribute ); + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20595,6 +20943,14 @@ THREE.WebGLRenderer = function ( parameters ) { var activeInfluenceIndices = []; var influences = object.morphTargetInfluences; + var morphTargets = object.geometry.morphTargets; + + if ( influences.length > morphTargets.length ) { + + console.warn( 'THREE.WebGLRenderer: Influences array is bigger than morphTargets array.' ); + influences.length = morphTargets.length; + + } for ( var i = 0, il = influences.length; i < il; i ++ ) { @@ -20632,7 +20988,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attribute >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); - enableAttribute( attribute ); + + state.enableAttribute( attribute ); + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20642,9 +21000,10 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attribute >= 0 && material.morphNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); - enableAttribute( attribute ); - _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); + state.enableAttribute( attribute ); + + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); } @@ -20684,7 +21043,11 @@ THREE.WebGLRenderer = function ( parameters ) { function painterSortStable ( a, b ) { - if ( a.material.id !== b.material.id ) { + if ( a.object.renderOrder !== b.object.renderOrder ) { + + return a.object.renderOrder - b.object.renderOrder; + + } else if ( a.material.id !== b.material.id ) { return a.material.id - b.material.id; @@ -20702,7 +21065,11 @@ THREE.WebGLRenderer = function ( parameters ) { function reversePainterSortStable ( a, b ) { - if ( a.z !== b.z ) { + if ( a.object.renderOrder !== b.object.renderOrder ) { + + return a.object.renderOrder - b.object.renderOrder; + + } if ( a.z !== b.z ) { return b.z - a.z; @@ -20726,7 +21093,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.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); return; } @@ -20819,32 +21186,27 @@ THREE.WebGLRenderer = function ( parameters ) { if ( scene.overrideMaterial ) { - var material = scene.overrideMaterial; + var overrideMaterial = scene.overrideMaterial; - this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - this.setDepthTest( material.depthTest ); - this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + setMaterial( overrideMaterial ); - renderObjects( opaqueObjects, camera, lights, fog, true, material ); - renderObjects( transparentObjects, camera, lights, fog, true, material ); - renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, false, material ); + renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial ); + renderObjects( transparentObjects, camera, lights, fog, overrideMaterial ); + renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial ); } else { - var material = null; - // opaque pass (front-to-back order) - this.setBlending( THREE.NoBlending ); + state.setBlending( THREE.NoBlending ); - renderObjects( opaqueObjects, camera, lights, fog, false, material ); - renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, false, material ); + renderObjects( opaqueObjects, camera, lights, fog, null ); + renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null ); // transparent pass (back-to-front order) - renderObjects( transparentObjects, camera, lights, fog, true, material ); - renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, true, material ); + renderObjects( transparentObjects, camera, lights, fog, null ); + renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null ); } @@ -20863,8 +21225,9 @@ THREE.WebGLRenderer = function ( parameters ) { // Ensure depth buffer writing is enabled so it can be cleared on next render - this.setDepthTest( true ); - this.setDepthWrite( true ); + state.setDepthTest( true ); + state.setDepthWrite( true ); + state.setColorWrite( true ); // _gl.finish(); @@ -20902,7 +21265,7 @@ THREE.WebGLRenderer = function ( parameters ) { for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { - var webglObject = webglObjects[i]; + var webglObject = webglObjects[ i ]; unrollBufferMaterial( webglObject ); @@ -20933,7 +21296,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - function renderObjects( renderList, camera, lights, fog, useBlending, overrideMaterial ) { + function renderObjects( renderList, camera, lights, fog, overrideMaterial ) { var material; @@ -20956,11 +21319,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( ! material ) continue; - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + setMaterial( material ); } @@ -20980,7 +21339,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) { var material; @@ -21001,11 +21360,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( ! material ) continue; - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + setMaterial( material ); } @@ -21377,20 +21732,36 @@ THREE.WebGLRenderer = function ( parameters ) { var key = attributesKeys[ i ]; var attribute = attributes[ key ]; + var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; if ( attribute.buffer === undefined ) { attribute.buffer = _gl.createBuffer(); - attribute.needsUpdate = true; - - } + _gl.bindBuffer( bufferType, attribute.buffer ); + _gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW ); - if ( attribute.needsUpdate === true ) { + attribute.needsUpdate = false; - var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; + } else if ( attribute.needsUpdate === true ) { _gl.bindBuffer( bufferType, attribute.buffer ); - _gl.bufferData( bufferType, attribute.array, _gl.STATIC_DRAW ); + + if ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges + + _gl.bufferSubData( bufferType, 0, attribute.array ); + + } else if ( attribute.updateRange.count === 0 ) { + + console.error( 'THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' ); + + } else { + + _gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT, + attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) ); + + attribute.updateRange.count = 0; // reset range + + } attribute.needsUpdate = false; @@ -21415,12 +21786,6 @@ THREE.WebGLRenderer = function ( parameters ) { var geometryGroup = geometryGroupsList[ i ]; var material = getBufferMaterial( object, geometryGroup ); - if ( geometry.groupsNeedUpdate === true ) { - - initMeshBuffers( geometryGroup, object ); - - } - var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || @@ -21610,6 +21975,8 @@ THREE.WebGLRenderer = function ( parameters ) { useFog: material.fog, fogExp: fog instanceof THREE.FogExp2, + flatShading: material.shading === THREE.FlatShading, + sizeAttenuation: material.sizeAttenuation, logarithmicDepthBuffer: _logarithmicDepthBuffer, @@ -21762,6 +22129,25 @@ THREE.WebGLRenderer = function ( parameters ) { } + function setMaterial( material ) { + + if ( material.transparent === true ) { + + state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); + + } else { + + state.setBlending( THREE.NoBlending ); + + } + + state.setDepthTest( material.depthTest ); + state.setDepthWrite( material.depthWrite ); + state.setColorWrite( material.colorWrite ); + state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + function setProgram( camera, lights, fog, material, object ) { _usedTextureUnits = 0; @@ -22014,15 +22400,7 @@ 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; @@ -22086,17 +22464,7 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.envMap.value = material.envMap; uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1; - if ( _this.gammaInput ) { - - //uniforms.reflectivity.value = material.reflectivity * material.reflectivity; - uniforms.reflectivity.value = material.reflectivity; - - } else { - - uniforms.reflectivity.value = material.reflectivity; - - } - + uniforms.reflectivity.value = material.reflectivity; uniforms.refractionRatio.value = material.refractionRatio; } @@ -22125,6 +22493,15 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.map.value = material.map; + if ( material.map !== null ) { + + var offset = material.map.offset; + var repeat = material.map.repeat; + + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + + } + } function refreshUniformsFog ( uniforms, fog ) { @@ -22148,17 +22525,8 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.shininess.value = material.shininess; - if ( _this.gammaInput ) { - - uniforms.emissive.value.copyGammaToLinear( material.emissive ); - uniforms.specular.value.copyGammaToLinear( material.specular ); - - } else { - - uniforms.emissive.value = material.emissive; - uniforms.specular.value = material.specular; - - } + uniforms.emissive.value = material.emissive; + uniforms.specular.value = material.specular; if ( material.wrapAround ) { @@ -22170,15 +22538,7 @@ THREE.WebGLRenderer = function ( parameters ) { function refreshUniformsLambert ( uniforms, material ) { - if ( _this.gammaInput ) { - - uniforms.emissive.value.copyGammaToLinear( material.emissive ); - - } else { - - uniforms.emissive.value = material.emissive; - - } + uniforms.emissive.value = material.emissive; if ( material.wrapAround ) { @@ -22198,6 +22558,7 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.pointLightColor.value = lights.point.colors; uniforms.pointLightPosition.value = lights.point.positions; uniforms.pointLightDistance.value = lights.point.distances; + uniforms.pointLightDecay.value = lights.point.decays; uniforms.spotLightColor.value = lights.spot.colors; uniforms.spotLightPosition.value = lights.spot.positions; @@ -22205,6 +22566,7 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.spotLightDirection.value = lights.spot.directions; uniforms.spotLightAngleCos.value = lights.spot.anglesCos; uniforms.spotLightExponent.value = lights.spot.exponents; + uniforms.spotLightDecay.value = lights.spot.decays; uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; @@ -22214,27 +22576,29 @@ THREE.WebGLRenderer = function ( parameters ) { // If uniforms are marked as clean, they don't need to be loaded to the GPU. - function markUniformsLightsNeedsUpdate ( uniforms, boolean ) { + function markUniformsLightsNeedsUpdate ( uniforms, value ) { - uniforms.ambientLightColor.needsUpdate = boolean; + uniforms.ambientLightColor.needsUpdate = value; - uniforms.directionalLightColor.needsUpdate = boolean; - uniforms.directionalLightDirection.needsUpdate = boolean; + uniforms.directionalLightColor.needsUpdate = value; + uniforms.directionalLightDirection.needsUpdate = value; - uniforms.pointLightColor.needsUpdate = boolean; - uniforms.pointLightPosition.needsUpdate = boolean; - uniforms.pointLightDistance.needsUpdate = boolean; + uniforms.pointLightColor.needsUpdate = value; + uniforms.pointLightPosition.needsUpdate = value; + uniforms.pointLightDistance.needsUpdate = value; + uniforms.pointLightDecay.needsUpdate = value; - uniforms.spotLightColor.needsUpdate = boolean; - uniforms.spotLightPosition.needsUpdate = boolean; - uniforms.spotLightDistance.needsUpdate = boolean; - uniforms.spotLightDirection.needsUpdate = boolean; - uniforms.spotLightAngleCos.needsUpdate = boolean; - uniforms.spotLightExponent.needsUpdate = boolean; + uniforms.spotLightColor.needsUpdate = value; + uniforms.spotLightPosition.needsUpdate = value; + uniforms.spotLightDistance.needsUpdate = value; + uniforms.spotLightDirection.needsUpdate = value; + uniforms.spotLightAngleCos.needsUpdate = value; + uniforms.spotLightExponent.needsUpdate = value; + uniforms.spotLightDecay.needsUpdate = value; - uniforms.hemisphereLightSkyColor.needsUpdate = boolean; - uniforms.hemisphereLightGroundColor.needsUpdate = boolean; - uniforms.hemisphereLightDirection.needsUpdate = boolean; + uniforms.hemisphereLightSkyColor.needsUpdate = value; + uniforms.hemisphereLightGroundColor.needsUpdate = value; + uniforms.hemisphereLightDirection.needsUpdate = value; } @@ -22290,7 +22654,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( textureUnit >= _maxTextures ) { - console.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures ); + THREE.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures ); } @@ -22628,7 +22992,7 @@ THREE.WebGLRenderer = function ( parameters ) { default: - console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); + THREE.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); } @@ -22643,16 +23007,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 ) { array[ offset ] = color.r * intensity; @@ -22663,11 +23017,10 @@ THREE.WebGLRenderer = function ( parameters ) { function setupLights ( lights ) { - var l, ll, light, n, + var l, ll, light, r = 0, g = 0, b = 0, color, skyColor, groundColor, - intensity, intensitySq, - position, + intensity, distance, zlights = _lights, @@ -22678,6 +23031,7 @@ THREE.WebGLRenderer = function ( parameters ) { pointColors = zlights.point.colors, pointPositions = zlights.point.positions, pointDistances = zlights.point.distances, + pointDecays = zlights.point.decays, spotColors = zlights.spot.colors, spotPositions = zlights.spot.positions, @@ -22685,6 +23039,7 @@ THREE.WebGLRenderer = function ( parameters ) { spotDirections = zlights.spot.directions, spotAnglesCos = zlights.spot.anglesCos, spotExponents = zlights.spot.exponents, + spotDecays = zlights.spot.decays, hemiSkyColors = zlights.hemi.skyColors, hemiGroundColors = zlights.hemi.groundColors, @@ -22719,19 +23074,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 ) { @@ -22750,15 +23095,7 @@ 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; @@ -22770,15 +23107,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 ); @@ -22786,7 +23115,9 @@ THREE.WebGLRenderer = function ( parameters ) { pointPositions[ pointOffset + 1 ] = _vector3.y; pointPositions[ pointOffset + 2 ] = _vector3.z; + // distance is 0 if decay is 0, because there is no attenuation at all. pointDistances[ pointLength ] = distance; + pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; pointLength += 1; @@ -22798,15 +23129,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 ); _direction.setFromMatrixPosition( light.matrixWorld ); @@ -22826,6 +23149,7 @@ THREE.WebGLRenderer = function ( parameters ) { spotAnglesCos[ spotLength ] = Math.cos( light.angle ); spotExponents[ spotLength ] = light.exponent; + spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; spotLength += 1; @@ -22847,19 +23171,8 @@ THREE.WebGLRenderer = function ( parameters ) { skyColor = light.color; groundColor = light.groundColor; - if ( _this.gammaInput ) { - - intensitySq = intensity * intensity; - - setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq ); - setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq ); - - } else { - - setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); - setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); - - } + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); hemiLength += 1; @@ -22929,197 +23242,8 @@ THREE.WebGLRenderer = function ( parameters ) { 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 ) { - - width *= pixelRatio; - - 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, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { - - 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 ) { - - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; - - if ( blendEquation !== _oldBlendEquation || blendEquationAlpha !== _oldBlendEquationAlpha ) { - - _gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); - - _oldBlendEquation = blendEquation; - _oldBlendEquationAlpha = blendEquationAlpha; - - } - - if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst || blendSrcAlpha !== _oldBlendSrcAlpha || blendDstAlpha !== _oldBlendDstAlpha ) { - - _gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); - - _oldBlendSrc = blendSrc; - _oldBlendDst = blendDst; - _oldBlendSrcAlpha = blendSrcAlpha; - _oldBlendDstAlpha = blendDstAlpha; - - } - - } else { - - _oldBlendEquation = null; - _oldBlendSrc = null; - _oldBlendDst = null; - _oldBlendEquationAlpha = null; - _oldBlendSrcAlpha = null; - _oldBlendDstAlpha = null; - - } + state.setDoubleSided( material.side === THREE.DoubleSide ); + state.setFlipSided( material.side === THREE.BackSide ); }; @@ -23144,7 +23268,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) { - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT is set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' ); + THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' ); } @@ -23153,7 +23277,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) { - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter is set to THREE.LinearFilter or THREE.NearestFilter. ( ' + texture.sourceFile + ' )' ); + THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' ); } @@ -23161,12 +23285,12 @@ THREE.WebGLRenderer = function ( parameters ) { extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - if ( extension && texture.type !== THREE.FloatType ) { + if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) { - if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { + if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) { _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) ); - texture.__oldAnisotropy = texture.anisotropy; + texture.__currentAnisotropy = texture.anisotropy; } @@ -23242,7 +23366,7 @@ THREE.WebGLRenderer = function ( parameters ) { } else { - console.warn( "Attempt to load unsupported compressed texture format" ); + THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); } @@ -23319,7 +23443,7 @@ THREE.WebGLRenderer = function ( parameters ) { var context = canvas.getContext( '2d' ); context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); - console.log( 'THREE.WebGLRenderer:', image, 'is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height + '.' ); + THREE.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); return canvas; @@ -23406,7 +23530,7 @@ THREE.WebGLRenderer = function ( parameters ) { } else { - console.warn( "Attempt to load unsupported compressed texture format" ); + THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" ); } @@ -23638,49 +23762,49 @@ THREE.WebGLRenderer = function ( parameters ) { this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) { - if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) { + if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - } + } - if ( renderTarget.__webglFramebuffer ) { + if ( renderTarget.__webglFramebuffer ) { - if ( renderTarget.format !== THREE.RGBAFormat ) { + if ( renderTarget.format !== THREE.RGBAFormat ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' ); - return; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' ); + return; - } + } - var restore = false; + var restore = false; - if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) { + if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) { - _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer ); - restore = true; + restore = true; - } + } - if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { + if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { - _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer ); + _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer ); - } else { + } else { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - } + } - if ( restore ) { + if ( restore ) { - _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); - } + } - } + } }; @@ -23746,6 +23870,14 @@ THREE.WebGLRenderer = function ( parameters ) { if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; if ( p === THREE.FloatType ) return _gl.FLOAT; + extension = extensions.get( 'OES_texture_half_float' ); + + if ( extension !== null ) { + + if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES; + + } + if ( p === THREE.AlphaFormat ) return _gl.ALPHA; if ( p === THREE.RGBFormat ) return _gl.RGB; if ( p === THREE.RGBAFormat ) return _gl.RGBA; @@ -23833,7 +23965,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( maxBones < object.skeleton.bones.length ) { - console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); + THREE.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); } @@ -23892,25 +24024,25 @@ THREE.WebGLRenderer = function ( parameters ) { this.initMaterial = function () { - console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); + THREE.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); }; this.addPrePlugin = function () { - console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); + THREE.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); }; this.addPostPlugin = function () { - console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); + THREE.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); }; this.updateShadowMap = function () { - console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); + THREE.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); }; @@ -24061,7 +24193,7 @@ THREE.WebGLExtensions = function ( gl ) { if ( extension === null ) { - console.log( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); + THREE.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); } @@ -24212,6 +24344,8 @@ THREE.WebGLProgram = ( function () { } + var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; + // console.log( 'building new program ' ); // @@ -24242,6 +24376,7 @@ THREE.WebGLProgram = ( function () { _this.gammaInput ? '#define GAMMA_INPUT' : '', _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, @@ -24262,6 +24397,8 @@ THREE.WebGLProgram = ( function () { parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.vertexColors ? '#define USE_COLOR' : '', + parameters.flatShading ? '#define FLAT_SHADED': '', + parameters.skinning ? '#define USE_SKINNING' : '', parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', @@ -24341,7 +24478,7 @@ THREE.WebGLProgram = ( function () { 'precision ' + parameters.precision + ' float;', 'precision ' + parameters.precision + ' int;', - ( parameters.bumpMap || parameters.normalMap ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', customDefines, @@ -24352,10 +24489,11 @@ THREE.WebGLProgram = ( function () { '#define MAX_SHADOWS ' + parameters.maxShadows, - parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest: '', + parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', _this.gammaInput ? '#define GAMMA_INPUT' : '', _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', @@ -24372,6 +24510,8 @@ THREE.WebGLProgram = ( function () { parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.vertexColors ? '#define USE_COLOR' : '', + parameters.flatShading ? '#define FLAT_SHADED': '', + parameters.metal ? '#define METAL' : '', parameters.wrapAround ? '#define WRAP_AROUND' : '', parameters.doubleSided ? '#define DOUBLE_SIDED' : '', @@ -24411,19 +24551,19 @@ THREE.WebGLProgram = ( function () { _gl.linkProgram( program ); + var programLogInfo = _gl.getProgramInfoLog( program ); + if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { - console.error( 'THREE.WebGLProgram: Could not initialise shader.' ); - console.error( 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) ); - console.error( 'gl.getError()', _gl.getError() ); + THREE.error( 'THREE.WebGLProgram: shader error: ' + _gl.getError(), 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), 'gl.getPRogramInfoLog', programLogInfo ); } - if ( _gl.getProgramInfoLog( program ) !== '' ) { + if ( programLogInfo !== '' ) { - console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', _gl.getProgramInfoLog( program ) ); - // console.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); - // console.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); + THREE.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()' + programLogInfo ); + // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); + // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); } @@ -24554,14 +24694,13 @@ THREE.WebGLShader = ( function () { if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { - console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); + THREE.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); } if ( gl.getShaderInfoLog( shader ) !== '' ) { - console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ) ); - console.warn( addLineNumbers( string ) ); + THREE.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); } @@ -24574,6 +24713,302 @@ THREE.WebGLShader = ( function () { } )(); +// File:src/renderers/webgl/WebGLState.js + +/** +* @author mrdoob / http://mrdoob.com/ +*/ + +THREE.WebGLState = function ( gl, paramThreeToGL ) { + + var newAttributes = new Uint8Array( 16 ); + var enabledAttributes = new Uint8Array( 16 ); + + var currentBlending = null; + var currentBlendEquation = null; + var currentBlendSrc = null; + var currentBlendDst = null; + var currentBlendEquationAlpha = null; + var currentBlendSrcAlpha = null; + var currentBlendDstAlpha = null; + + var currentDepthTest = null; + var currentDepthWrite = null; + + var currentColorWrite = null; + + var currentDoubleSided = null; + var currentFlipSided = null; + + var currentLineWidth = null; + + var currentPolygonOffset = null; + var currentPolygonOffsetFactor = null; + var currentPolygonOffsetUnits = null; + + this.initAttributes = function () { + + for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { + + newAttributes[ i ] = 0; + + } + + }; + + this.enableAttribute = function ( attribute ) { + + newAttributes[ attribute ] = 1; + + if ( enabledAttributes[ attribute ] === 0 ) { + + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; + + } + + }; + + this.disableUnusedAttributes = function () { + + for ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) { + + if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { + + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; + + } + + } + + }; + + this.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { + + if ( blending !== currentBlending ) { + + 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 ); + + } + + currentBlending = blending; + + } + + if ( blending === THREE.CustomBlending ) { + + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; + + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { + + gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); + + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; + + } + + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { + + gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); + + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; + + } + + } else { + + currentBlendEquation = null; + currentBlendSrc = null; + currentBlendDst = null; + currentBlendEquationAlpha = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; + + } + + }; + + this.setDepthTest = function ( depthTest ) { + + if ( currentDepthTest !== depthTest ) { + + if ( depthTest ) { + + gl.enable( gl.DEPTH_TEST ); + + } else { + + gl.disable( gl.DEPTH_TEST ); + + } + + currentDepthTest = depthTest; + + } + + }; + + this.setDepthWrite = function ( depthWrite ) { + + if ( currentDepthWrite !== depthWrite ) { + + gl.depthMask( depthWrite ); + currentDepthWrite = depthWrite; + + } + + }; + + this.setColorWrite = function ( colorWrite ) { + + if ( currentColorWrite !== colorWrite ) { + + gl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite ); + currentColorWrite = colorWrite; + + } + + }; + + this.setDoubleSided = function ( doubleSided ) { + + if ( currentDoubleSided !== doubleSided ) { + + if ( doubleSided ) { + + gl.disable( gl.CULL_FACE ); + + } else { + + gl.enable( gl.CULL_FACE ); + + } + + currentDoubleSided = doubleSided; + + } + + }; + + this.setFlipSided = function ( flipSided ) { + + if ( currentFlipSided !== flipSided ) { + + if ( flipSided ) { + + gl.frontFace( gl.CW ); + + } else { + + gl.frontFace( gl.CCW ); + + } + + currentFlipSided = flipSided; + + } + + }; + + this.setLineWidth = function ( width ) { + + if ( width !== currentLineWidth ) { + + gl.lineWidth( width ); + + currentLineWidth = width; + + } + + }; + + this.setPolygonOffset = function ( polygonoffset, factor, units ) { + + if ( currentPolygonOffset !== polygonoffset ) { + + if ( polygonoffset ) { + + gl.enable( gl.POLYGON_OFFSET_FILL ); + + } else { + + gl.disable( gl.POLYGON_OFFSET_FILL ); + + } + + currentPolygonOffset = polygonoffset; + + } + + if ( polygonoffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) { + + gl.polygonOffset( factor, units ); + + currentPolygonOffsetFactor = factor; + currentPolygonOffsetUnits = units; + + } + + }; + + this.reset = function () { + + for ( var i = 0; i < enabledAttributes.length; i ++ ) { + + enabledAttributes[ i ] = 0; + + } + + currentBlending = null; + currentDepthTest = null; + currentDepthWrite = null; + currentColorWrite = null; + currentDoubleSided = null; + currentFlipSided = null; + + }; + +}; + // File:src/renderers/webgl/plugins/LensFlarePlugin.js /** @@ -24899,7 +25334,7 @@ THREE.LensFlarePlugin = function ( renderer, flares ) { // calc object screen position var flare = flares[ i ]; - + tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); tempPosition.applyMatrix4( camera.matrixWorldInverse ); @@ -24997,7 +25432,7 @@ THREE.LensFlarePlugin = function ( renderer, flares ) { 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.state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); renderer.setTexture( sprite.texture, 1 ); gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); @@ -25065,7 +25500,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje _max = new THREE.Vector3(), _matrixPosition = new THREE.Vector3(), - + _renderList = []; // init @@ -25113,7 +25548,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje var i, il, j, jl, n, shadowMap, shadowMatrix, shadowCamera, - program, buffer, material, + buffer, material, webglObject, object, light, lights = [], @@ -25139,7 +25574,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje } - _renderer.setDepthTest( true ); + _renderer.state.setDepthTest( true ); // preprocess lights // - skip lights that are not casting shadows @@ -25172,7 +25607,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje light.shadowCascadeArray[ n ] = virtualLight; - console.log( "Created virtualLight", virtualLight ); + //console.log( "Created virtualLight", virtualLight ); } else { @@ -25233,7 +25668,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje } else { - console.error( "Unsupported light type for shadow" ); + THREE.error( "THREE.ShadowMapPlugin: Unsupported light type for shadow", light ); continue; } @@ -25398,7 +25833,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje }; - function projectObject( scene, object, shadowCamera ){ + function projectObject( scene, object, shadowCamera ) { if ( object.visible ) { @@ -25789,9 +26224,9 @@ THREE.SpritePlugin = function ( renderer, sprites ) { 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 ); + renderer.state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + renderer.state.setDepthTest( material.depthTest ); + renderer.state.setDepthWrite( material.depthWrite ); if ( material.map && material.map.image && material.map.image.width ) { @@ -25948,7 +26383,7 @@ THREE.GeometryUtils = { merge: function ( geometry1, geometry2, materialIndexOffset ) { - console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); + THREE.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); var matrix; @@ -25967,7 +26402,7 @@ THREE.GeometryUtils = { center: function ( geometry ) { - console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); + THREE.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); return geometry.center(); } @@ -26059,13 +26494,13 @@ THREE.ImageUtils = { loadCompressedTexture: function () { - console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) + THREE.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) }, loadCompressedTextureCube: function () { - console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) + THREE.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) }, @@ -26122,7 +26557,7 @@ THREE.ImageUtils = { 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, - 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 ] ); @@ -26301,7 +26736,7 @@ THREE.FontUtils = { 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; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; return data; @@ -26309,11 +26744,9 @@ THREE.FontUtils = { drawText: function ( text ) { - var characterPts = [], allPts = []; - // RenderText - var i, p, + var i, face = this.getFace(), scale = this.size / face.resolution, offset = 0, @@ -26401,7 +26834,7 @@ THREE.FontUtils = { x = outline[ i ++ ] * scaleX + offset; y = outline[ i ++ ] * scaleY; - path.lineTo( x,y ); + path.lineTo( x, y ); break; case 'q': @@ -26425,13 +26858,13 @@ THREE.FontUtils = { 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 ); - } + THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + } - } + } - break; + break; case 'b': @@ -26456,8 +26889,8 @@ THREE.FontUtils = { 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 ); + THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); } @@ -26578,7 +27011,7 @@ THREE.FontUtils.generateShapes = function ( text, parameters ) { //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.warn( 'THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()' ); if ( indices ) return vertIndices; return result; @@ -26612,7 +27045,7 @@ THREE.FontUtils.generateShapes = function ( text, parameters ) { /* remove v from the remaining polygon */ - for ( s = v, t = v + 1; t < nv; s++, t++ ) { + for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { verts[ s ] = verts[ t ]; @@ -26728,6 +27161,7 @@ THREE.Audio = function ( listener ) { this.context = listener.context; this.source = this.context.createBufferSource(); + this.source.onended = this.onEnded.bind(this); this.gain = this.context.createGain(); this.gain.connect( this.context.destination ); @@ -26735,6 +27169,11 @@ THREE.Audio = function ( listener ) { this.panner = this.context.createPanner(); this.panner.connect( this.gain ); + this.autoplay = false; + + this.startTime = 0; + this.isPlaying = false; + }; THREE.Audio.prototype = Object.create( THREE.Object3D.prototype ); @@ -26752,8 +27191,8 @@ THREE.Audio.prototype.load = function ( file ) { scope.context.decodeAudioData( this.response, function ( buffer ) { scope.source.buffer = buffer; - scope.source.connect( scope.panner ); - scope.source.start( 0 ); + + if( scope.autoplay ) scope.play(); } ); @@ -26764,6 +27203,49 @@ THREE.Audio.prototype.load = function ( file ) { }; +THREE.Audio.prototype.play = function () { + + if ( this.isPlaying === true ) { + + THREE.warn( 'THREE.Audio: Audio is already playing.' ); + return; + + } + + var source = this.context.createBufferSource(); + + source.buffer = this.source.buffer; + source.loop = this.source.loop; + source.onended = this.source.onended; + source.connect( this.panner ); + source.start( 0, this.startTime ); + + this.isPlaying = true; + + this.source = source; + +}; + +THREE.Audio.prototype.pause = function () { + + this.source.stop(); + this.startTime = this.context.currentTime; + +}; + +THREE.Audio.prototype.stop = function () { + + this.source.stop(); + this.startTime = 0; + +}; + +THREE.Audio.prototype.onEnded = function() { + + this.isPlaying = false; + +}; + THREE.Audio.prototype.setLoop = function ( value ) { this.source.loop = value; @@ -26782,6 +27264,12 @@ THREE.Audio.prototype.setRolloffFactor = function ( value ) { }; +THREE.Audio.prototype.setVolume = function ( value ) { + + this.gain.gain.value = value; + +}; + THREE.Audio.prototype.updateMatrixWorld = ( function () { var position = new THREE.Vector3(); @@ -26897,7 +27385,7 @@ THREE.Curve = function () { THREE.Curve.prototype.getPoint = function ( t ) { - console.log( "Warning, getPoint() not implemented!" ); + THREE.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); return null; }; @@ -26961,7 +27449,7 @@ THREE.Curve.prototype.getLength = function () { THREE.Curve.prototype.getLengths = function ( divisions ) { - if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200; + if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200; if ( this.cacheArcLengths && ( this.cacheArcLengths.length == divisions + 1 ) @@ -27036,12 +27524,10 @@ THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { if ( comparison < 0 ) { low = i + 1; - continue; } else if ( comparison > 0 ) { high = i - 1; - continue; } else { @@ -27068,17 +27554,17 @@ THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { // we could get finer grain at lengths, or use simple interpolatation between two points var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; + var lengthAfter = arcLengths[ i + 1 ]; - var segmentLength = lengthAfter - lengthBefore; + var segmentLength = lengthAfter - lengthBefore; // determine where we are between the 'before' and 'after' points - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; // add that fractional amount to t - var t = ( i + segmentFraction ) / ( il -1 ); + var t = ( i + segmentFraction ) / ( il - 1 ); return t; @@ -27137,8 +27623,8 @@ THREE.Curve.Utils = { 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 * p1 * (1 - t) * (1 - t) - 6 * t * p1 * (1 - t) + + 6 * t * p2 * (1 - t) - 3 * t * t * p2 + 3 * t * t * p3; }, @@ -27229,7 +27715,7 @@ THREE.CurvePath.prototype.closePath = function() { // 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); + var endPoint = this.curves[this.curves.length - 1].getPoint(1); if (! startPoint.equals(endPoint)) { this.curves.push( new THREE.LineCurve(endPoint, startPoint) ); @@ -27265,7 +27751,6 @@ THREE.CurvePath.prototype.getPoint = function( t ) { return curve.getPointAt( u ); - break; } i ++; @@ -27818,7 +28303,7 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) { action = item.action; args = item.args; - switch( action ) { + switch ( action ) { case THREE.PathActions.MOVE_TO: @@ -27965,7 +28450,7 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) { //console.log(points); - break; + break; case THREE.PathActions.ELLIPSE: @@ -28003,7 +28488,7 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) { //console.log(points); - break; + break; } // end switch @@ -28110,7 +28595,7 @@ THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { // 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 ++ ) { + for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { var edgeLowPt = inPolygon[ p ]; var edgeHighPt = inPolygon[ q ]; @@ -28223,7 +28708,6 @@ THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { 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]; @@ -28442,16 +28926,16 @@ THREE.Shape.Utils = { if ( perpSeg2 == 0 ) { if ( ( inExcludeAdjacentSegs ) && ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; - return [ inSeg1Pt1 ]; + return [ inSeg1Pt1 ]; } if ( perpSeg2 == limit ) { if ( ( inExcludeAdjacentSegs ) && ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; - return [ inSeg1Pt2 ]; + return [ inSeg1Pt2 ]; } // intersection at endpoint of segment#2? - if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ]; - if ( perpSeg1 == limit ) return [ inSeg2Pt2 ]; + if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ]; + if ( perpSeg1 == limit ) return [ inSeg2Pt2 ]; // return real intersection point var factorSeg1 = perpSeg2 / limit; @@ -28469,17 +28953,17 @@ THREE.Shape.Utils = { if ( seg1Pt && seg2Pt ) { if ( (inSeg1Pt1.x != inSeg2Pt1.x) || (inSeg1Pt1.y != inSeg2Pt1.y) ) return []; // they are distinct points - return [ inSeg1Pt1 ]; // they are the same point + 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 ]; + 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 ]; + return [ inSeg2Pt1 ]; } // they are collinear segments, which might overlap @@ -28610,7 +29094,7 @@ THREE.Shape.Utils = { // checks for intersections with shape edges var sIdx, nextIdx, intersection; for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) { - nextIdx = sIdx+1; nextIdx %= shape.length; + nextIdx = sIdx + 1; nextIdx %= shape.length; intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true ); if ( intersection.length > 0 ) return true; } @@ -28627,7 +29111,7 @@ THREE.Shape.Utils = { for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) { chkHole = holes[indepHoles[ihIdx]]; for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) { - nextIdx = hIdx+1; nextIdx %= chkHole.length; + nextIdx = hIdx + 1; nextIdx %= chkHole.length; intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true ); if ( intersection.length > 0 ) return true; } @@ -28679,12 +29163,12 @@ THREE.Shape.Utils = { if ( intersectsHoleEdge( shapePt, holePt ) ) continue; holeIndex = h2; - indepHoles.splice(h,1); + indepHoles.splice(h, 1); - tmpShape1 = shape.slice( 0, shapeIndex+1 ); + tmpShape1 = shape.slice( 0, shapeIndex + 1 ); tmpShape2 = shape.slice( shapeIndex ); tmpHole1 = hole.slice( holeIndex ); - tmpHole2 = hole.slice( 0, holeIndex+1 ); + tmpHole2 = hole.slice( 0, holeIndex + 1 ); shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); @@ -28731,7 +29215,7 @@ THREE.Shape.Utils = { if ( allPointsMap[ key ] !== undefined ) { - console.log( "Duplicate point", key ); + THREE.warn( "THREE.Shape: Duplicate point", key ); } @@ -28998,8 +29482,8 @@ THREE.SplineCurve.prototype.getPoint = function ( t ) { var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ] var point1 = points[ intPoint ] - var point2 = points[ intPoint > points.length - 2 ? points.length -1 : intPoint + 1 ] - var point3 = points[ intPoint > points.length - 3 ? points.length -1 : intPoint + 2 ] + var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ] + var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ] var vector = new THREE.Vector2(); @@ -29262,9 +29746,9 @@ THREE.AnimationHandler = { // - add: function () { console.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); }, - get: function () { console.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); }, - remove: function () { console.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); }, + add: function () { THREE.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); }, + get: function () { THREE.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); }, + remove: function () { THREE.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); }, // @@ -29491,7 +29975,7 @@ THREE.Animation.prototype.keyTypes = [ "pos", "rot", "scl" ]; THREE.Animation.prototype.play = function ( startTime, weight ) { this.currentTime = startTime !== undefined ? startTime : 0; - this.weight = weight !== undefined ? weight: 1; + this.weight = weight !== undefined ? weight : 1; this.isPlaying = true; @@ -29582,7 +30066,7 @@ THREE.Animation.prototype.resetBlendWeights = function () { }; -THREE.Animation.prototype.update = (function(){ +THREE.Animation.prototype.update = (function() { var points = []; var target = new THREE.Vector3(); @@ -30385,7 +30869,7 @@ THREE.CircleGeometry.prototype.constructor = THREE.CircleGeometry; THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - console.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' ); + THREE.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' ); return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ); }; @@ -30692,7 +31176,6 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var ahole, h, hl; // looping of holes var scope = this; - var bevelPoints = []; var shapesOffset = this.vertices.length; @@ -30732,7 +31215,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var contour = vertices; // vertices has all points but contour has only points of circumference - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; @@ -30743,7 +31226,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { function scalePt2 ( pt, vec, size ) { - if ( ! vec ) console.log( "die" ); + if ( ! vec ) THREE.error( "THREE.ExtrudeGeometry: vec does not exist" ); return vec.clone().multiplyScalar( size ).add( pt ); @@ -30751,14 +31234,11 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var b, bs, t, z, vert, vlen = vertices.length, - face, flen = faces.length, - cont, clen = contour.length; + face, flen = faces.length; // Find directions for point movement - var RAD_TO_DEGREES = 180 / Math.PI; - function getBevelVec( inPt, inPrev, inNext ) { @@ -30861,11 +31341,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { // (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 ] ); + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); } @@ -30883,7 +31359,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { if ( k === il ) k = 0; // (j)---(i)---(k) - oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); } @@ -30902,7 +31378,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { z = bevelThickness * ( 1 - t ); //z = bevelThickness * t; - bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved + bs = bevelSize * ( Math.sin ( t * Math.PI / 2 ) ) ; // curved //bs = bevelSize * t ; // linear // contract shape @@ -31002,7 +31478,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { 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 ) ; + bs = bevelSize * Math.sin ( t * Math.PI / 2 ) ; // contract shape @@ -31065,7 +31541,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; - f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset ); + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); } @@ -31112,7 +31588,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { sidewalls( contour, layeroffset ); layeroffset += contour.length; - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; sidewalls( ahole, layeroffset ); @@ -31129,7 +31605,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var j, k; i = contour.length; - while ( --i >= 0 ) { + while ( -- i >= 0 ) { j = i; k = i - 1; @@ -31174,7 +31650,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var uvs = uvgen.generateTopUV( scope, a, b, c ); - scope.faceVertexUvs[ 0 ].push( uvs ); + scope.faceVertexUvs[ 0 ].push( uvs ); } @@ -31185,13 +31661,13 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { 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 ) ); + 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, a, b, c, d ); + var uvs = uvgen.generateSideWallUV( scope, a, b, c, d ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); } @@ -31305,7 +31781,7 @@ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { // - var i, l, hole, s; + var i, l, hole; var shapesOffset = this.vertices.length; var shapePoints = shape.extractPoints( curveSegments ); @@ -31354,7 +31830,6 @@ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { var vert, vlen = vertices.length; var face, flen = faces.length; - var cont, clen = contour.length; for ( i = 0; i < vlen; i ++ ) { @@ -32127,8 +32602,6 @@ THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed, numpoints = segments + 1, - x, y, z, - tx, ty, tz, u, v, r, cx, cy, @@ -32239,9 +32712,7 @@ THREE.TubeGeometry.SinusoidalTaper = function ( u ) { // 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(), + var normal = new THREE.Vector3(), tangents = [], normals = [], @@ -32256,7 +32727,7 @@ THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { smallest, tx, ty, tz, - i, u, v; + i, u; // expose internals @@ -32337,17 +32808,17 @@ THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { for ( i = 1; i < numpoints; i ++ ) { - normals[ i ] = normals[ i-1 ].clone(); + normals[ i ] = normals[ i - 1 ].clone(); - binormals[ i ] = binormals[ i-1 ].clone(); + binormals[ i ] = binormals[ i - 1 ].clone(); - vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); + 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 + 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 ) ); @@ -32362,10 +32833,10 @@ THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { if ( closed ) { - theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), - 1, 1 ) ); + 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 ) { + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints - 1 ] ) ) > 0 ) { theta = - theta; @@ -32414,7 +32885,7 @@ THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { } - var midpoints = [], p = this.vertices; + var p = this.vertices; var faces = []; @@ -32522,7 +32993,6 @@ THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { 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 ] ); @@ -32807,10 +33277,9 @@ THREE.ParametricGeometry = function ( func, slices, stacks ) { var faces = this.faces; var uvs = this.faceVertexUvs[ 0 ]; - var i, il, j, p; + var i, j, p; var u, v; - var stackCount = stacks + 1; var sliceCount = slices + 1; for ( i = 0; i <= stacks; i ++ ) { @@ -33429,11 +33898,20 @@ THREE.DirectionalLightHelper.prototype.update = function () { /** * @author WestLangley / http://github.com/WestLangley + * @param object THREE.Mesh whose geometry will be used + * @param hex line color + * @param thresholdAngle the minimim angle (in degrees), + * between the face normals of adjacent faces, + * that is required to render an edge. A value of 10 means + * an edge is only rendered if the angle is at least 10 degrees. */ -THREE.EdgesHelper = function ( object, hex ) { +THREE.EdgesHelper = function ( object, hex, thresholdAngle ) { var color = ( hex !== undefined ) ? hex : 0xffffff; + thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; + + var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) ); var edge = [ 0, 0 ], hash = {}; var sortFunction = function ( a, b ) { return a - b }; @@ -33441,7 +33919,18 @@ THREE.EdgesHelper = function ( object, hex ) { var keys = [ 'a', 'b', 'c' ]; var geometry = new THREE.BufferGeometry(); - var geometry2 = object.geometry.clone(); + var geometry2; + + if ( object.geometry instanceof THREE.BufferGeometry ) { + + geometry2 = new THREE.Geometry(); + geometry2.fromBufferGeometry( object.geometry ); + + } else { + + geometry2 = object.geometry.clone(); + + } geometry2.mergeVertices(); geometry2.computeFaceNormals(); @@ -33485,7 +33974,7 @@ THREE.EdgesHelper = function ( object, hex ) { var h = hash[ key ]; - if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) < 0.9999 ) { // hardwired const OK + if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) { var vertex = vertices[ h.vert1 ]; coords[ index ++ ] = vertex.x; @@ -33641,7 +34130,7 @@ THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { * @author mrdoob / http://mrdoob.com/ */ -THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { +THREE.HemisphereLightHelper = function ( light, sphereSize ) { THREE.Object3D.call( this ); @@ -33953,8 +34442,6 @@ THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { 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 ++ ) { @@ -34056,8 +34543,6 @@ THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { 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 ++ ) { @@ -34414,7 +34899,6 @@ THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { if ( chunks && chunks.length > 1 ) { var name = chunks[ 1 ]; - var num = chunks[ 2 ]; if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity }; @@ -34559,7 +35043,7 @@ THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { } else { - console.warn( "animation[" + name + "] undefined" ); + THREE.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); } diff --git a/build/three.min.js b/build/three.min.js index e409bba567c7fc..5084a609d9e43e 100644 --- a/build/three.min.js +++ b/build/three.min.js @@ -1,18 +1,19 @@ // threejs.org/license -'use strict';var THREE={REVISION:"71dev"};"object"===typeof module&&(module.exports=THREE);void 0===Math.sign&&(Math.sign=function(a){return 0>a?-1:0a?-1:0>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(a,b,c){if(0===b)this.r=this.g=this.b=c;else{var d=function(a,b,c){0>c&&(c+=1);1c?b:c<2/3?a+6*(b-a)*(2/3-c):a};b=.5>=c?c*(1+b):c+b-c*b;c=2*c-b;this.r=d(c,b,a+1/3);this.g=d(c,b,a);this.b=d(c,b,a-1/3)}return this},setStyle:function(a){if(/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test(a))return a=/^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec(a),this.r=Math.min(255,parseInt(a[1],10))/255,this.g=Math.min(255,parseInt(a[2],10))/255,this.b=Math.min(255,parseInt(a[3],10))/255,this;if(/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test(a))return a=/^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec(a),this.r= Math.min(100,parseInt(a[1],10))/100,this.g=Math.min(100,parseInt(a[2],10))/100,this.b=Math.min(100,parseInt(a[3],10))/100,this;if(/^\#([0-9a-f]{6})$/i.test(a))return a=/^\#([0-9a-f]{6})$/i.exec(a),this.setHex(parseInt(a[1],16)),this;if(/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(a))return a=/^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(a),this.setHex(parseInt(a[1]+a[1]+a[2]+a[2]+a[3]+a[3],16)),this;if(/^(\w+)$/i.test(a))return this.setHex(THREE.ColorKeywords[a]),this},copy:function(a){this.r=a.r;this.g= -a.g;this.b=a.b;return this},copyGammaToLinear:function(a){this.r=a.r*a.r;this.g=a.g*a.g;this.b=a.b*a.b;return this},copyLinearToGamma:function(a){this.r=Math.sqrt(a.r);this.g=Math.sqrt(a.g);this.b=Math.sqrt(a.b);return this},convertGammaToLinear:function(){var a=this.r,b=this.g,c=this.b;this.r=a*a;this.g=b*b;this.b=c*c;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 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){a=a||{h:0,s:0,l:0};var b=this.r,c=this.g,d=this.b,e=Math.max(b,c,d),f=Math.min(b,c,d),g,h=(f+e)/2;if(f===e)f=g=0;else{var k=e-f,f=.5>=h?k/(e+f):k/(2-e-f);switch(e){case b:g=(c-d)/k+(c=h?k/(e+f):k/(2-e-f);switch(e){case b:g=(c-d)/k+(cf&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(k-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-h)/c,this._x=(a+e)/c,this._y= +b){var c=b/2,d=Math.sin(c);this._x=a.x*d;this._y=a.y*d;this._z=a.z*d;this._w=Math.cos(c);this.onChangeCallback();return this},setFromRotationMatrix:function(a){var b=a.elements,c=b[0];a=b[4];var d=b[8],e=b[1],f=b[5],g=b[9],h=b[2],k=b[6],b=b[10],l=c+f+b;0f&&c>b?(c=2*Math.sqrt(1+c-f-b),this._w=(k-g)/c,this._x=.25*c,this._y=(a+e)/c,this._z=(d+h)/c):f>b?(c=2*Math.sqrt(1+f-c-b),this._w=(d-h)/c,this._x=(a+e)/c,this._y= .25*c,this._z=(g+k)/c):(c=2*Math.sqrt(1+b-c-f),this._w=(e-a)/c,this._x=(d+h)/c,this._y=(g+k)/c,this._z=.25*c);this.onChangeCallback();return this},setFromUnitVectors:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3);b=c.dot(d)+1;1E-6>b?(b=0,Math.abs(c.x)>Math.abs(c.z)?a.set(-c.y,c.x,0):a.set(0,-c.z,c.y)):a.crossVectors(c,d);this._x=a.x;this._y=a.y;this._z=a.z;this._w=b;this.normalize();return this}}(),inverse:function(){this.conjugate().normalize();return this},conjugate:function(){this._x*= -1;this._y*=-1;this._z*=-1;this.onChangeCallback();return this},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)},normalize:function(){var a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this.onChangeCallback();return this}, -multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .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,k=b._z,n=b._w;this._x=c*n+f*g+d*k-e*h;this._y=d*n+f*h+e*g-c*k;this._z=e*n+f*k+c*h-d*g;this._w=f*n-c*g-d*h-e*k;this.onChangeCallback();return this},multiplyVector3:function(a){console.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."); +multiply:function(a,b){return void 0!==b?(THREE.warn("THREE.Quaternion: .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,k=b._z,l=b._w;this._x=c*l+f*g+d*k-e*h;this._y=d*l+f*h+e*g-c*k;this._z=e*l+f*k+c*h-d*g;this._w=f*l-c*g-d*h-e*k;this.onChangeCallback();return this},multiplyVector3:function(a){THREE.warn("THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead."); return a.applyQuaternion(this)},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);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;0>g?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,g=-g):this.copy(a);if(1<=g)return this._w=f,this._x=c,this._y=d,this._z=e,this;var h=Math.acos(g),k=Math.sqrt(1-g*g);if(.001>Math.abs(k))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;g=Math.sin((1-b)*h)/k;h= Math.sin(b*h)/k;this._w=f*g+this._w*h;this._x=c*g+this._x*h;this._y=d*g+this._y*h;this._z=e*g+this._z*h;this.onChangeCallback();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._w;return a},onChange:function(a){this.onChangeCallback= a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Quaternion(this._x,this._y,this._z,this._w)}};THREE.Quaternion.slerp=function(a,b,c,d){return c.copy(a).slerp(b,d)};THREE.Vector2=function(a,b){this.x=a||0;this.y=b||0}; THREE.Vector2.prototype={constructor:THREE.Vector2,set:function(a,b){this.x=a;this.y=b;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a, -b){if(void 0!==b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this}, -subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a):this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector2,b=new THREE.Vector2);a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},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;a=this.y-a.y;return b*b+a*a},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x; -a[b+1]=this.y;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];return this},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; +b){if(void 0!==b)return THREE.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},sub:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this}, +subScalar:function(a){this.x-=a;this.y-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a):this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector2,b=new THREE.Vector2);a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},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;a=this.y-a.y;return b*b+a*a},setLength:function(a){var b=this.length();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0=== +a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];return this},clone:function(){return new THREE.Vector2(this.x,this.y)}};THREE.Vector3=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0}; THREE.Vector3.prototype={constructor:THREE.Vector3,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return 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 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 Error("index is out of range: "+ -a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .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;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;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(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .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;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(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .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;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;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 a;return function(b){!1===b instanceof THREE.Euler&&console.error("THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.");void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromEuler(b));return this}}(),applyAxisAngle:function(){var a;return function(b,c){void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromAxisAngle(b,c));return this}}(),applyMatrix3:function(a){var b=this.x, -c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z= -(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var h=a*b+f*d-g*c,k=a*c+g*b-e*d,n=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+k*-g-n*-f;this.y=k*a+b*-f+n*-e-h*-g;this.z=n*a+b*-g+h*-f-k*-e;return this},project:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyProjection(a)}}(),unproject:function(){var a;return function(b){void 0=== -a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyProjection(a)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a):this.z=this.y=this.x=0;return this},min:function(a){this.x> -a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3,b=new THREE.Vector3);a.set(c,c,c);b.set(d,d,d);return this.clamp(a, -b)}}(),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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z); -return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},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();0!==b&&a!==b&&this.multiplyScalar(a/ -b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},cross:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .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;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c= -a.x,d=a.y,e=a.z,f=b.x,g=b.y,h=b.z;this.x=d*h-e*g;this.y=e*f-c*h;this.z=c*g-d*f;return this},projectOnVector:function(){var a,b;return function(c){void 0===a&&(a=new THREE.Vector3);a.copy(c).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);return this.sub(a.copy(b).multiplyScalar(2* -this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/(this.length()*a.length());return Math.acos(THREE.Math.clamp(a,-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;a=this.z-a.z;return b*b+c*c+a*a},setEulerFromRotationMatrix:function(a,b){console.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")},setEulerFromQuaternion:function(a,b){console.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")}, -getPositionFromMatrix:function(a){console.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().");return this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){console.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().");return this.setFromMatrixScale(a)},getColumnFromMatrix:function(a,b){console.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().");return this.setFromMatrixColumn(a, -b)},setFromMatrixPosition:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return 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();a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a;return this},setFromMatrixColumn:function(a,b){var c=4*a,d=b.elements;this.x=d[c];this.y=d[c+1];this.z=d[c+2];return this},equals:function(a){return a.x=== -this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z=a.array[b+2];return this},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}}; -THREE.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}; +a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector3: .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;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;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(a,b){if(void 0!==b)return THREE.warn("THREE.Vector3: .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;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;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(a,b){if(void 0!==b)return THREE.warn("THREE.Vector3: .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;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*= +a;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 a;return function(b){!1===b instanceof THREE.Euler&&THREE.error("THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.");void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromEuler(b));return this}}(),applyAxisAngle:function(){var a;return function(b,c){void 0===a&&(a=new THREE.Quaternion);this.applyQuaternion(a.setFromAxisAngle(b, +c));return this}}(),applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12];this.y=a[1]*b+a[5]*c+a[9]*d+a[13];this.z=a[2]*b+a[6]*c+a[10]*d+a[14];return this},applyProjection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;var e=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]* +c+a[8]*d+a[12])*e;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*e;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*e;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,e=a.x,f=a.y,g=a.z;a=a.w;var h=a*b+f*d-g*c,k=a*c+g*b-e*d,l=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+k*-g-l*-f;this.y=k*a+b*-f+l*-e-h*-g;this.z=l*a+b*-g+h*-f-k*-e;return this},project:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyProjection(a)}}(), +unproject:function(){var a;return function(b){void 0===a&&(a=new THREE.Matrix4);a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyProjection(a)}}(),transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;this.normalize();return this},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*= +a):this.z=this.y=this.x=0;return this},min:function(a){this.x>a.x&&(this.x=a.x);this.y>a.y&&(this.y=a.y);this.z>a.z&&(this.z=a.z);return this},max:function(a){this.xb.x&&(this.x=b.x);this.yb.y&&(this.y=b.y);this.zb.z&&(this.z=b.z);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector3, +b=new THREE.Vector3);a.set(c,c,c);b.set(d,d,d);return this.clamp(a,b)}}(),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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y): +Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},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();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},cross:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector3: .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;this.x=d*a.z-e*a.y;this.y= +e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},crossVectors:function(a,b){var c=a.x,d=a.y,e=a.z,f=b.x,g=b.y,h=b.z;this.x=d*h-e*g;this.y=e*f-c*h;this.z=c*g-d*f;return this},projectOnVector:function(){var a,b;return function(c){void 0===a&&(a=new THREE.Vector3);a.copy(c).normalize();b=this.dot(a);return this.copy(a).multiplyScalar(b)}}(),projectOnPlane:function(){var a;return function(b){void 0===a&&(a=new THREE.Vector3);a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a;return function(b){void 0=== +a&&(a=new THREE.Vector3);return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/(this.length()*a.length());return Math.acos(THREE.Math.clamp(a,-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;a=this.z-a.z;return b*b+c*c+a*a},setEulerFromRotationMatrix:function(a,b){THREE.error("THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.")}, +setEulerFromQuaternion:function(a,b){THREE.error("THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.")},getPositionFromMatrix:function(a){THREE.warn("THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().");return this.setFromMatrixPosition(a)},getScaleFromMatrix:function(a){THREE.warn("THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().");return this.setFromMatrixScale(a)},getColumnFromMatrix:function(a, +b){THREE.warn("THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().");return this.setFromMatrixColumn(a,b)},setFromMatrixPosition:function(a){this.x=a.elements[12];this.y=a.elements[13];this.z=a.elements[14];return 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();a=this.set(a.elements[8],a.elements[9],a.elements[10]).length();this.x=b;this.y=c;this.z=a; +return this},setFromMatrixColumn:function(a,b){var c=4*a,d=b.elements;this.x=d[c];this.y=d[c+1];this.z=d[c+2];return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z= +a.array[b+2];return this},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)}};THREE.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}; THREE.Vector4.prototype={constructor:THREE.Vector4,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return 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 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 Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .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;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;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(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .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;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(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b= -this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a):(this.z=this.y=this.x=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);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this}, -setAxisAngleFromRotationMatrix:function(a){var b,c,d;a=a.elements;var e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],k=a[9];c=a[2];b=a[6];var n=a[10];if(.01>Math.abs(d-g)&&.01>Math.abs(f-c)&&.01>Math.abs(k-b)){if(.1>Math.abs(d+g)&&.1>Math.abs(f+c)&&.1>Math.abs(k+b)&&.1>Math.abs(e+h+n-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;n=(n+1)/2;d=(d+g)/4;f=(f+c)/4;k=(k+b)/4;e>h&&e>n?.01>e?(b=0,d=c=.707106781):(b=Math.sqrt(e),c=d/b,d=f/b):h>n?.01>h?(b=.707106781,c=0,d=.707106781):(c=Math.sqrt(h), -b=d/c,d=k/c):.01>n?(c=b=.707106781,d=0):(d=Math.sqrt(n),b=f/d,c=k/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-k)*(b-k)+(f-c)*(f-c)+(g-d)*(g-d));.001>Math.abs(a)&&(a=1);this.x=(b-k)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+n-1)/2);return this},min:function(a){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);return this},max:function(a){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);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector4,b=new THREE.Vector4);a.set(c,c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w); -return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},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();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){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;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a, -b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]=this.w;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z=a.array[b+2];this.w=a.array[b+3];return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}};THREE.Euler=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||THREE.Euler.DefaultOrder};THREE.Euler.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" "); -THREE.Euler.DefaultOrder="XYZ"; +case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return THREE.warn("THREE.Vector4: .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;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;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(a,b){if(void 0!==b)return THREE.warn("THREE.Vector4: .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;return this},subScalar:function(a){this.x-=a;this.y-=a;this.z-=a;this.w-=a;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(a){this.x*= +a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,e=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*e;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*e;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*e;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*e;return this},divideScalar:function(a){0!==a?(a=1/a,this.x*=a,this.y*=a,this.z*=a,this.w*=a):(this.z=this.y=this.x=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);1E-4> +b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){var b,c,d;a=a.elements;var e=a[0];d=a[4];var f=a[8],g=a[1],h=a[5],k=a[9];c=a[2];b=a[6];var l=a[10];if(.01>Math.abs(d-g)&&.01>Math.abs(f-c)&&.01>Math.abs(k-b)){if(.1>Math.abs(d+g)&&.1>Math.abs(f+c)&&.1>Math.abs(k+b)&&.1>Math.abs(e+h+l-3))return this.set(1,0,0,0),this;a=Math.PI;e=(e+1)/2;h=(h+1)/2;l=(l+1)/2;d=(d+g)/4;f=(f+c)/4;k=(k+b)/4;e>h&&e>l?.01>e?(b=0,d=c=.707106781):(b= +Math.sqrt(e),c=d/b,d=f/b):h>l?.01>h?(b=.707106781,c=0,d=.707106781):(c=Math.sqrt(h),b=d/c,d=k/c):.01>l?(c=b=.707106781,d=0):(d=Math.sqrt(l),b=f/d,c=k/d);this.set(b,c,d,a);return this}a=Math.sqrt((b-k)*(b-k)+(f-c)*(f-c)+(g-d)*(g-d));.001>Math.abs(a)&&(a=1);this.x=(b-k)/a;this.y=(f-c)/a;this.z=(g-d)/a;this.w=Math.acos((e+h+l-1)/2);return this},min:function(a){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);return this},max:function(a){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);return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new THREE.Vector4,b=new THREE.Vector4);a.set(c,c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),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=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y); +this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},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();0!==b&&a!==b&&this.multiplyScalar(a/b);return this},lerp:function(a,b){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;return this},lerpVectors:function(a,b,c){this.subVectors(b,a).multiplyScalar(c).add(a);return this},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w}, +fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]=this.w;return a},fromAttribute:function(a,b,c){void 0===c&&(c=0);b=b*a.itemSize+c;this.x=a.array[b];this.y=a.array[b+1];this.z=a.array[b+2];this.w=a.array[b+3];return this},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)}}; +THREE.Euler=function(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||THREE.Euler.DefaultOrder};THREE.Euler.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" ");THREE.Euler.DefaultOrder="XYZ"; THREE.Euler.prototype={constructor:THREE.Euler,_x:0,_y:0,_z:0,_order:THREE.Euler.DefaultOrder,get x(){return this._x},set x(a){this._x=a;this.onChangeCallback()},get y(){return this._y},set y(a){this._y=a;this.onChangeCallback()},get z(){return this._z},set z(a){this._z=a;this.onChangeCallback()},get order(){return this._order},set order(a){this._order=a;this.onChangeCallback()},set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this.onChangeCallback();return this},copy:function(a){this._x= -a._x;this._y=a._y;this._z=a._z;this._order=a._order;this.onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=THREE.Math.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],h=e[1],k=e[5],n=e[9],p=e[2],q=e[6],e=e[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(d(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(-n,e),this._z=Math.atan2(-f,a)):(this._x=Math.atan2(q,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(n,-1,1)),.99999>Math.abs(n)?(this._y=Math.atan2(g,e),this._z=Math.atan2(h, -k)):(this._y=Math.atan2(-p,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(q,-1,1)),.99999>Math.abs(q)?(this._y=Math.atan2(-p,e),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,a))):"ZYX"===b?(this._y=Math.asin(-d(p,-1,1)),.99999>Math.abs(p)?(this._x=Math.atan2(q,e),this._z=Math.atan2(h,a)):(this._x=0,this._z=Math.atan2(-f,k))):"YZX"===b?(this._z=Math.asin(d(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-n,k),this._y=Math.atan2(-p,a)):(this._x=0,this._y=Math.atan2(g,e))):"XZY"===b?(this._z= -Math.asin(-d(f,-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(q,k),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-n,e),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback();return this},setFromQuaternion:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Matrix4);a.makeRotationFromQuaternion(b);this.setFromRotationMatrix(a,c,d);return this}}(),setFromVector3:function(a,b){return this.set(a.x,a.y,a.z, -b||this._order)},reorder:function(){var a=new THREE.Quaternion;return function(b){a.setFromEuler(this);this.setFromQuaternion(a,b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(){return[this._x,this._y,this._z,this._order]},toVector3:function(a){return a?a.set(this._x,this._y,this._z):new THREE.Vector3(this._x, -this._y,this._z)},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Euler(this._x,this._y,this._z,this._order)}};THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; +a._x;this._y=a._y;this._z=a._z;this._order=a._order;this.onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=THREE.Math.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],h=e[1],k=e[5],l=e[9],p=e[2],q=e[6],e=e[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(d(g,-1,1)),.99999>Math.abs(g)?(this._x=Math.atan2(-l,e),this._z=Math.atan2(-f,a)):(this._x=Math.atan2(q,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(l,-1,1)),.99999>Math.abs(l)?(this._y=Math.atan2(g,e),this._z=Math.atan2(h, +k)):(this._y=Math.atan2(-p,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(q,-1,1)),.99999>Math.abs(q)?(this._y=Math.atan2(-p,e),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,a))):"ZYX"===b?(this._y=Math.asin(-d(p,-1,1)),.99999>Math.abs(p)?(this._x=Math.atan2(q,e),this._z=Math.atan2(h,a)):(this._x=0,this._z=Math.atan2(-f,k))):"YZX"===b?(this._z=Math.asin(d(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-l,k),this._y=Math.atan2(-p,a)):(this._x=0,this._y=Math.atan2(g,e))):"XZY"===b?(this._z= +Math.asin(-d(f,-1,1)),.99999>Math.abs(f)?(this._x=Math.atan2(q,k),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-l,e),this._y=0)):THREE.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;if(!1!==c)this.onChangeCallback();return this},setFromQuaternion:function(){var a;return function(b,c,d){void 0===a&&(a=new THREE.Matrix4);a.makeRotationFromQuaternion(b);this.setFromRotationMatrix(a,c,d);return this}}(),setFromVector3:function(a,b){return this.set(a.x,a.y,a.z, +b||this._order)},reorder:function(){var a=new THREE.Quaternion;return function(b){a.setFromEuler(this);this.setFromQuaternion(a,b)}}(),equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this.onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._order;return a},toVector3:function(a){return a? +a.set(this._x,this._y,this._z):new THREE.Vector3(this._x,this._y,this._z)},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){},clone:function(){return new THREE.Euler(this._x,this._y,this._z,this._order)}};THREE.Line3=function(a,b){this.start=void 0!==a?a:new THREE.Vector3;this.end=void 0!==b?b:new THREE.Vector3}; THREE.Line3.prototype={constructor:THREE.Line3,set:function(a,b){this.start.copy(a);this.end.copy(b);return this},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},center:function(a){return(a||new THREE.Vector3).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){return(a||new THREE.Vector3).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 THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);var e=b.dot(b),e=b.dot(a)/e;d&&(e=THREE.Math.clamp(e,0,1));return e}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new THREE.Vector3;return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a); this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)},clone:function(){return(new THREE.Line3).copy(this)}};THREE.Box2=function(a,b){this.min=void 0!==a?a:new THREE.Vector2(Infinity,Infinity);this.max=void 0!==b?b:new THREE.Vector2(-Infinity,-Infinity)}; @@ -86,39 +87,39 @@ this.max.add(a);return this},expandByScalar:function(a){this.min.addScalar(-a);t 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){return(b||new THREE.Vector3).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new THREE.Vector3;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a= new THREE.Vector3;return function(b){b=b||new THREE.Sphere;b.center=this.center();b.radius=.5*this.size(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a=[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(b){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);return this}}(),translate:function(a){this.min.add(a); -this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)},clone:function(){return(new THREE.Box3).copy(this)}};THREE.Matrix3=function(){this.elements=new Float32Array([1,0,0,0,1,0,0,0,1]);0this.determinant()&&(g=-g);c.x=f[12]; -c.y=f[13];c.z=f[14];b.elements.set(this.elements);c=1/g;var f=1/h,n=1/k;b.elements[0]*=c;b.elements[1]*=c;b.elements[2]*=c;b.elements[4]*=f;b.elements[5]*=f;b.elements[6]*=f;b.elements[8]*=n;b.elements[9]*=n;b.elements[10]*=n;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makeFrustum:function(a,b,c,d,e,f){var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(d-c);g[9]=(d+c)/(d-c);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0;g[7]=0; -g[11]=-1;g[15]=0;return this},makePerspective:function(a,b,c,d){a=c*Math.tan(THREE.Math.degToRad(.5*a));var e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=b-a,k=c-d,n=f-e;g[0]=2/h;g[4]=0;g[8]=0;g[12]=-((b+a)/h);g[1]=0;g[5]=2/k;g[9]=0;g[13]=-((c+d)/k);g[2]=0;g[6]=0;g[10]=-2/n;g[14]=-((f+e)/n);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},fromArray:function(a){this.elements.set(a);return this},toArray:function(){var a=this.elements;return[a[0], +f=1/a.set(b[8],b[9],b[10]).length();c[0]=b[0]*d;c[1]=b[1]*d;c[2]=b[2]*d;c[4]=b[4]*e;c[5]=b[5]*e;c[6]=b[6]*e;c[8]=b[8]*f;c[9]=b[9]*f;c[10]=b[10]*f;return this}}(),makeRotationFromEuler:function(a){!1===a instanceof THREE.Euler&&THREE.error("THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,e=a.z,f=Math.cos(c),c=Math.sin(c),g=Math.cos(d),d=Math.sin(d),h=Math.cos(e),e=Math.sin(e);if("XYZ"===a.order){a=f*h;var k=f*e, +l=c*h,p=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=k+l*d;b[5]=a-p*d;b[9]=-c*g;b[2]=p-a*d;b[6]=l+k*d;b[10]=f*g}else"YXZ"===a.order?(a=g*h,k=g*e,l=d*h,p=d*e,b[0]=a+p*c,b[4]=l*c-k,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=k*c-l,b[6]=p+a*c,b[10]=f*g):"ZXY"===a.order?(a=g*h,k=g*e,l=d*h,p=d*e,b[0]=a-p*c,b[4]=-f*e,b[8]=l+k*c,b[1]=k+l*c,b[5]=f*h,b[9]=p-a*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(a=f*h,k=f*e,l=c*h,p=c*e,b[0]=g*h,b[4]=l*d-k,b[8]=a*d+p,b[1]=g*e,b[5]=p*d+a,b[9]=k*d-l,b[2]=-d,b[6]=c*g,b[10]=f*g):"YZX"=== +a.order?(a=f*g,k=f*d,l=c*g,p=c*d,b[0]=g*h,b[4]=p-a*e,b[8]=l*e+k,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=k*e+l,b[10]=a-p*e):"XZY"===a.order&&(a=f*g,k=f*d,l=c*g,p=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=a*e+p,b[5]=f*h,b[9]=k*e-l,b[2]=l*e-k,b[6]=c*h,b[10]=p*e+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},setRotationFromQuaternion:function(a){THREE.warn("THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().");return 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,k=e+e;a=c*g;var l=c*h,c=c*k,p=d*h,d=d*k,e=e*k,g=f*g,h=f*h,f=f*k;b[0]=1-(p+e);b[4]=l-f;b[8]=c+h;b[1]=l+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+p);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},lookAt:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f){var g=this.elements;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;return this}}(),multiply:function(a,b){return void 0!==b?(THREE.warn("THREE.Matrix4: .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], +k=c[12],l=c[1],p=c[5],q=c[9],n=c[13],t=c[2],r=c[6],s=c[10],u=c[14],v=c[3],x=c[7],D=c[11],c=c[15],w=d[0],y=d[4],A=d[8],E=d[12],G=d[1],F=d[5],z=d[9],I=d[13],U=d[2],M=d[6],H=d[10],L=d[14],P=d[3],N=d[7],R=d[11],d=d[15];e[0]=f*w+g*G+h*U+k*P;e[4]=f*y+g*F+h*M+k*N;e[8]=f*A+g*z+h*H+k*R;e[12]=f*E+g*I+h*L+k*d;e[1]=l*w+p*G+q*U+n*P;e[5]=l*y+p*F+q*M+n*N;e[9]=l*A+p*z+q*H+n*R;e[13]=l*E+p*I+q*L+n*d;e[2]=t*w+r*G+s*U+u*P;e[6]=t*y+r*F+s*M+u*N;e[10]=t*A+r*z+s*H+u*R;e[14]=t*E+r*I+s*L+u*d;e[3]=v*w+x*G+D*U+c*P;e[7]=v*y+ +x*F+D*M+c*N;e[11]=v*A+x*z+D*H+c*R;e[15]=v*E+x*I+D*L+c*d;return this},multiplyToArray:function(a,b,c){var d=this.elements;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];return this},multiplyScalar:function(a){var b=this.elements;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;return this},multiplyVector3:function(a){THREE.warn("THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.");return a.applyProjection(this)},multiplyVector4:function(a){THREE.warn("THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.");return a.applyMatrix4(this)},multiplyVector3Array:function(a){THREE.warn("THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead."); +return this.applyToVector3Array(a)},applyToVector3Array:function(){var a=new THREE.Vector3;return function(b,c,d){void 0===c&&(c=0);void 0===d&&(d=b.length);for(var e=0;ethis.determinant()&&(g=-g);c.x=f[12]; +c.y=f[13];c.z=f[14];b.elements.set(this.elements);c=1/g;var f=1/h,l=1/k;b.elements[0]*=c;b.elements[1]*=c;b.elements[2]*=c;b.elements[4]*=f;b.elements[5]*=f;b.elements[6]*=f;b.elements[8]*=l;b.elements[9]*=l;b.elements[10]*=l;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makeFrustum:function(a,b,c,d,e,f){var g=this.elements;g[0]=2*e/(b-a);g[4]=0;g[8]=(b+a)/(b-a);g[12]=0;g[1]=0;g[5]=2*e/(d-c);g[9]=(d+c)/(d-c);g[13]=0;g[2]=0;g[6]=0;g[10]=-(f+e)/(f-e);g[14]=-2*f*e/(f-e);g[3]=0;g[7]=0; +g[11]=-1;g[15]=0;return this},makePerspective:function(a,b,c,d){a=c*Math.tan(THREE.Math.degToRad(.5*a));var e=-a;return this.makeFrustum(e*b,a*b,e,a,c,d)},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=b-a,k=c-d,l=f-e;g[0]=2/h;g[4]=0;g[8]=0;g[12]=-((b+a)/h);g[1]=0;g[5]=2/k;g[9]=0;g[13]=-((c+d)/k);g[2]=0;g[6]=0;g[10]=-2/l;g[14]=-((f+e)/l);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},fromArray:function(a){this.elements.set(a);return 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(){return(new THREE.Matrix4).fromArray(this.elements)}};THREE.Ray=function(a,b){this.origin=void 0!==a?a:new THREE.Vector3;this.direction=void 0!==b?b:new THREE.Vector3}; THREE.Ray.prototype={constructor:THREE.Ray,set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){return(b||new THREE.Vector3).copy(this.direction).multiplyScalar(a).add(this.origin)},recast:function(){var a=new THREE.Vector3;return function(b){this.origin.copy(this.at(b,a));return this}}(),closestPointToPoint:function(a,b){var c=b||new THREE.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 THREE.Vector3;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceTo(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceTo(b)}}(),distanceSqToSegment:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3;return function(d,e,f,g){a.copy(d).add(e).multiplyScalar(.5); -b.copy(e).sub(d).normalize();c.copy(this.origin).sub(a);var h=.5*d.distanceTo(e),k=-this.direction.dot(b),n=c.dot(this.direction),p=-c.dot(b),q=c.lengthSq(),m=Math.abs(1-k*k),t;0=-t?e<=t?(h=1/m,d*=h,e*=h,k=d*(d+k*e+2*n)+e*(k*d+e+2*p)+q):(e=h,d=Math.max(0,-(k*e+n)),k=-d*d+e*(e+2*p)+q):(e=-h,d=Math.max(0,-(k*e+n)),k=-d*d+e*(e+2*p)+q):e<=-t?(d=Math.max(0,-(-k*h+n)),e=0=-t?e<=t?(h=1/n,d*=h,e*=h,k=d*(d+k*e+2*l)+e*(k*d+e+2*p)+q):(e=h,d=Math.max(0,-(k*e+l)),k=-d*d+e*(e+2*p)+q):(e=-h,d=Math.max(0,-(k*e+l)),k=-d*d+e*(e+2*p)+q):e<=-t?(d=Math.max(0,-(-k*h+l)),e=0f)return null;f=Math.sqrt(f-e);e=d-f;d+=f;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),isIntersectionPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0==b)return 0==a.distanceToPoint(this.origin)?0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){var c=this.distanceToPlane(a);return null===c?null:this.at(c,b)}, isIntersectionBox:function(){var a=new THREE.Vector3;return function(b){return null!==this.intersectBox(b,a)}}(),intersectBox:function(a,b){var c,d,e,f,g;d=1/this.direction.x;f=1/this.direction.y;g=1/this.direction.z;var h=this.origin;0<=d?(c=(a.min.x-h.x)*d,d*=a.max.x-h.x):(c=(a.max.x-h.x)*d,d*=a.min.x-h.x);0<=f?(e=(a.min.y-h.y)*f,f*=a.max.y-h.y):(e=(a.max.y-h.y)*f,f*=a.min.y-h.y);if(c>f||e>d)return null;if(e>c||c!==c)c=e;if(fg||e>d)return null;if(e>c||c!==c)c=e;if(gd?null:this.at(0<=c?c:d,b)},intersectTriangle:function(){var a=new THREE.Vector3,b=new THREE.Vector3,c=new THREE.Vector3,d=new THREE.Vector3;return function(e,f,g,h,k){b.subVectors(f,e);c.subVectors(g,e);d.crossVectors(b,c);f=this.direction.dot(d);if(0f)h=-1,f=-f;else return null;a.subVectors(this.origin,e);e=h*this.direction.dot(c.crossVectors(a,c));if(0>e)return null;g=h*this.direction.dot(b.cross(a)); @@ -127,8 +128,8 @@ THREE.Sphere.prototype={constructor:THREE.Sphere,set:function(a,b){this.center.c 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 THREE.Vector3;d.copy(a);c>this.radius*this.radius&&(d.sub(this.center).normalize(),d.multiplyScalar(this.radius).add(this.center));return d},getBoundingBox:function(a){a=a||new THREE.Box3;a.set(this.center,this.center);a.expandByScalar(this.radius); return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius},clone:function(){return(new THREE.Sphere).copy(this)}}; THREE.Frustum=function(a,b,c,d,e,f){this.planes=[void 0!==a?a:new THREE.Plane,void 0!==b?b:new THREE.Plane,void 0!==c?c:new THREE.Plane,void 0!==d?d:new THREE.Plane,void 0!==e?e:new THREE.Plane,void 0!==f?f:new THREE.Plane]}; -THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return 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;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],n=c[7],p=c[8],q=c[9],m=c[10],t=c[11],s=c[12],r=c[13],u=c[14],c=c[15];b[0].setComponents(f-a,n-g,t-p,c-s).normalize();b[1].setComponents(f+ -a,n+g,t+p,c+s).normalize();b[2].setComponents(f+d,n+h,t+q,c+r).normalize();b[3].setComponents(f-d,n-h,t-q,c-r).normalize();b[4].setComponents(f-e,n-k,t-m,c-u).normalize();b[5].setComponents(f+e,n+k,t+m,c+u).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes, +THREE.Frustum.prototype={constructor:THREE.Frustum,set:function(a,b,c,d,e,f){var g=this.planes;g[0].copy(a);g[1].copy(b);g[2].copy(c);g[3].copy(d);g[4].copy(e);g[5].copy(f);return 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;a=c[0];var d=c[1],e=c[2],f=c[3],g=c[4],h=c[5],k=c[6],l=c[7],p=c[8],q=c[9],n=c[10],t=c[11],r=c[12],s=c[13],u=c[14],c=c[15];b[0].setComponents(f-a,l-g,t-p,c-r).normalize();b[1].setComponents(f+ +a,l+g,t+p,c+r).normalize();b[2].setComponents(f+d,l+h,t+q,c+s).normalize();b[3].setComponents(f-d,l-h,t-q,c-s).normalize();b[4].setComponents(f-e,l-k,t-n,c-u).normalize();b[5].setComponents(f+e,l+k,t+n,c+u).normalize();return this},intersectsObject:function(){var a=new THREE.Sphere;return function(b){var c=b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere);a.applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSphere:function(a){var b=this.planes, c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)e;e++){var f=d[e];a.x=0g&&0>f)return!1}return!0}}(), containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0},clone:function(){return(new THREE.Frustum).copy(this)}};THREE.Plane=function(a,b){this.normal=void 0!==a?a:new THREE.Vector3(1,0,0);this.constant=void 0!==b?b:0}; THREE.Plane.prototype={constructor:THREE.Plane,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d, @@ -138,12 +139,12 @@ coplanarPoint:function(a){return(a||new THREE.Vector3).copy(this.normal).multipl a.constant==this.constant},clone:function(){return(new THREE.Plane).copy(this)}}; THREE.Math={generateUUID:function(){var a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".split(""),b=Array(36),c=0,d;return function(){for(var e=0;36>e;e++)8==e||13==e||18==e||23==e?b[e]="-":14==e?b[e]="4":(2>=c&&(c=33554432+16777216*Math.random()|0),d=c&15,c>>=4,b[e]=a[19==e?d&3|8:d]);return b.join("")}}(),clamp:function(a,b,c){return ac?c:a},clampBottom:function(a,b){return a=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},random16:function(){return(65280*Math.random()+255*Math.random())/65535},randInt:function(a,b){return Math.floor(this.randFloat(a,b))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},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}}; -THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,k,n,p,q,m;this.initFromArray=function(a){this.points=[];for(var b=0;bthis.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1:f+ -2;n=this.points[c[0]];p=this.points[c[1]];q=this.points[c[2]];m=this.points[c[3]];h=g*g;k=g*h;d.x=b(n.x,p.x,q.x,m.x,g,h,k);d.y=b(n.y,p.y,q.y,m.y,g,h,k);d.z=b(n.z,p.z,q.z,m.z,g,h,k);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a>1;a|=a>>2;a|=a>>4;a|=a>>8;a|=a>>16;a++;return a}}; +THREE.Spline=function(a){function b(a,b,c,d,e,f,g){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*g+(-3*(b-c)-2*a-d)*f+a*e+b}this.points=a;var c=[],d={x:0,y:0,z:0},e,f,g,h,k,l,p,q,n;this.initFromArray=function(a){this.points=[];for(var b=0;bthis.points.length-2?this.points.length-1:f+1;c[3]=f>this.points.length-3?this.points.length-1:f+ +2;l=this.points[c[0]];p=this.points[c[1]];q=this.points[c[2]];n=this.points[c[3]];h=g*g;k=g*h;d.x=b(l.x,p.x,q.x,n.x,g,h,k);d.y=b(l.y,p.y,q.y,n.y,g,h,k);d.z=b(l.z,p.z,q.z,n.z,g,h,k);return d};this.getControlPointsArray=function(){var a,b,c=this.points.length,d=[];for(a=0;a=b.x+b.y}}(); 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(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]);return this},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},area:function(){var a=new THREE.Vector3,b=new THREE.Vector3;return function(){a.subVectors(this.c,this.b);b.subVectors(this.a,this.b);return.5*a.cross(b).length()}}(),midpoint:function(a){return(a|| new THREE.Vector3).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return THREE.Triangle.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new THREE.Plane).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return THREE.Triangle.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return THREE.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)}, @@ -153,79 +154,81 @@ a=.001*(b-this.oldTime);this.oldTime=b;this.elapsedTime+=a}return a}};THREE.Even THREE.EventDispatcher.prototype={constructor:THREE.EventDispatcher,apply:function(a){a.addEventListener=THREE.EventDispatcher.prototype.addEventListener;a.hasEventListener=THREE.EventDispatcher.prototype.hasEventListener;a.removeEventListener=THREE.EventDispatcher.prototype.removeEventListener;a.dispatchEvent=THREE.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[a];if(void 0!==c){var d=c.indexOf(b);-1!==d&&c.splice(d,1)}}},dispatchEvent:function(a){if(void 0!==this._listeners){var b=this._listeners[a.type];if(void 0!==b){a.target=this;for(var c=[],d=b.length,e=0;eya?-1:1;h[4*a]=ga.x;h[4*a+1]=ga.y;h[4*a+2]=ga.z;h[4*a+3]=$a}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal||void 0===this.attributes.uv)console.warn("Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var c=this.attributes.index.array,d=this.attributes.position.array, -e=this.attributes.normal.array,f=this.attributes.uv.array,g=d.length/3;void 0===this.attributes.tangent&&this.addAttribute("tangent",new THREE.BufferAttribute(new Float32Array(4*g),4));for(var h=this.attributes.tangent.array,k=[],n=[],p=0;pr;r++)s=a[3*c+r],-1==m[s]?(q[2*r]=s,q[2*r+1]=-1,p++):m[s]k.index+b)for(k={start:f,count:0,index:g},h.push(k),p=0;6>p;p+=2)r=q[p+1],-1p;p+=2)s=q[p],r=q[p+1],-1===r&&(r=g++),m[s]=r,t[r]=s,e[f++]=r-k.index,k.count++}this.reorderBuffers(e,t,g);return this.offsets=h},merge:function(a,b){if(!1===a instanceof THREE.BufferGeometry)console.error("THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.",a);else{void 0===b&&(b=0);var c=this.attributes,d;for(d in c)if(void 0!==a.attributes[d])for(var e=c[d].array,f=a.attributes[d],g=f.array,h=0,f=f.itemSize*b;hqa?-1:1;h[4*a]=oa.x;h[4*a+1]=oa.y;h[4*a+2]=oa.z;h[4*a+3]=ca}if(void 0===this.attributes.index||void 0===this.attributes.position||void 0===this.attributes.normal|| +void 0===this.attributes.uv)THREE.warn("THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()");else{var c=this.attributes.index.array,d=this.attributes.position.array,e=this.attributes.normal.array,f=this.attributes.uv.array,g=d.length/3;void 0===this.attributes.tangent&&this.addAttribute("tangent",new THREE.BufferAttribute(new Float32Array(4*g),4));for(var h=this.attributes.tangent.array,k=[],l=[],p=0;p +s;s++)r=b[3*c+s],-1==n[r]?(q[2*s]=r,q[2*s+1]=-1,p++):n[r]k.index+a)for(k={start:f,count:0,index:g},h.push(k),p=0;6>p;p+=2)s=q[p+1],-1p;p+=2)r=q[p],s=q[p+1],-1===s&&(s=g++),n[r]=s,t[s]=r,e[f++]=s-k.index,k.count++}this.reorderBuffers(e,t,g);return this.drawcalls=this.offsets=h},merge:function(a,b){if(!1===a instanceof THREE.BufferGeometry)THREE.error("THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.", +a);else{void 0===b&&(b=0);var c=this.attributes,d;for(d in c)if(void 0!==a.attributes[d])for(var e=c[d].array,f=a.attributes[d],g=f.array,h=0,f=f.itemSize*b;hd?-1:1,e.vertexTangents[c]=new THREE.Vector4(x.x,x.y,x.z,d);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;cd;d++)if(e[d]==e[(d+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(e=a[f],this.faces.splice(e,1),c=0,g=this.faceVertexUvs.length;cd?-1:1,e.vertexTangents[c]=new THREE.Vector4(w.x,w.y,w.z,d);this.hasTangents=!0},computeLineDistances:function(){for(var a=0,b=this.vertices,c=0,d=b.length;cd;d++)if(e[d]==e[(d+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(e=a[f],this.faces.splice(e,1),c=0,g=this.faceVertexUvs.length;ca.opacity)h.transparent=a.transparent;void 0!==a.depthTest&&(h.depthTest=a.depthTest);void 0!==a.depthWrite&&(h.depthWrite=a.depthWrite);void 0!==a.visible&&(h.visible=a.visible);void 0!==a.flipSided&&(h.side=THREE.BackSide);void 0!==a.doubleSided&&(h.side=THREE.DoubleSide);void 0!==a.wireframe&&(h.wireframe=a.wireframe);void 0!==a.vertexColors&&("face"=== -a.vertexColors?h.vertexColors=THREE.FaceColors:a.vertexColors&&(h.vertexColors=THREE.VertexColors));a.colorDiffuse?h.color=e(a.colorDiffuse):a.DbgColor&&(h.color=a.DbgColor);a.colorSpecular&&(h.specular=e(a.colorSpecular));a.colorEmissive&&(h.emissive=e(a.colorEmissive));a.transparency&&(h.opacity=a.transparency);a.specularCoef&&(h.shininess=a.specularCoef);a.mapDiffuse&&b&&d(h,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&d(h,"lightMap", -a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&d(h,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&d(h,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&d(h,"specularMap",a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapAlpha&&b&&d(h,"alphaMap",a.mapAlpha,a.mapAlphaRepeat,a.mapAlphaOffset, -a.mapAlphaWrap,a.mapAlphaAnisotropy);a.mapBumpScale&&(h.bumpScale=a.mapBumpScale);a.mapNormalFactor&&(h.normalScale=new THREE.Vector2(a.mapNormalFactor,a.mapNormalFactor));g=new THREE[g](h);void 0!==a.DbgName&&(g.name=a.DbgName);return g}};THREE.Loader.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=0,c=this.handlers.length;ba.opacity&&(h.transparent=!0);void 0!==a.depthTest&&(h.depthTest=a.depthTest);void 0!==a.depthWrite&&(h.depthWrite=a.depthWrite);void 0!==a.visible&&(h.visible=a.visible);void 0!==a.flipSided&&(h.side=THREE.BackSide);void 0!==a.doubleSided&&(h.side=THREE.DoubleSide);void 0!==a.wireframe&&(h.wireframe=a.wireframe); +void 0!==a.vertexColors&&("face"===a.vertexColors?h.vertexColors=THREE.FaceColors:a.vertexColors&&(h.vertexColors=THREE.VertexColors));a.colorDiffuse?h.color=e(a.colorDiffuse):a.DbgColor&&(h.color=a.DbgColor);a.colorSpecular&&(h.specular=e(a.colorSpecular));a.colorEmissive&&(h.emissive=e(a.colorEmissive));void 0!==a.transparency&&(console.warn("THREE.Loader: transparency has been renamed to opacity"),a.opacity=a.transparency);void 0!==a.opacity&&(h.opacity=a.opacity);a.specularCoef&&(h.shininess= +a.specularCoef);a.mapDiffuse&&b&&d(h,"map",a.mapDiffuse,a.mapDiffuseRepeat,a.mapDiffuseOffset,a.mapDiffuseWrap,a.mapDiffuseAnisotropy);a.mapLight&&b&&d(h,"lightMap",a.mapLight,a.mapLightRepeat,a.mapLightOffset,a.mapLightWrap,a.mapLightAnisotropy);a.mapBump&&b&&d(h,"bumpMap",a.mapBump,a.mapBumpRepeat,a.mapBumpOffset,a.mapBumpWrap,a.mapBumpAnisotropy);a.mapNormal&&b&&d(h,"normalMap",a.mapNormal,a.mapNormalRepeat,a.mapNormalOffset,a.mapNormalWrap,a.mapNormalAnisotropy);a.mapSpecular&&b&&d(h,"specularMap", +a.mapSpecular,a.mapSpecularRepeat,a.mapSpecularOffset,a.mapSpecularWrap,a.mapSpecularAnisotropy);a.mapAlpha&&b&&d(h,"alphaMap",a.mapAlpha,a.mapAlphaRepeat,a.mapAlphaOffset,a.mapAlphaWrap,a.mapAlphaAnisotropy);a.mapBumpScale&&(h.bumpScale=a.mapBumpScale);a.mapNormalFactor&&(h.normalScale=new THREE.Vector2(a.mapNormalFactor,a.mapNormalFactor));g=new THREE[g](h);void 0!==a.DbgName&&(g.name=a.DbgName);return g}}; +THREE.Loader.Handlers={handlers:[],add:function(a,b){this.handlers.push(a,b)},get:function(a){for(var b=0,c=this.handlers.length;bg;g++)m=y[k++],v=u[2*m],m=u[2*m+1],v=new THREE.Vector2(v,m),2!==g&&c.faceVertexUvs[d][h].push(v),0!==g&&c.faceVertexUvs[d][h+1].push(v);q&&(q=3*y[k++],t.normal.set(C[q++],C[q++],C[q]),r.normal.copy(t.normal));if(s)for(d=0;4>d;d++)q=3*y[k++],s=new THREE.Vector3(C[q++], -C[q++],C[q]),2!==d&&t.vertexNormals.push(s),0!==d&&r.vertexNormals.push(s);p&&(p=y[k++],p=x[p],t.color.setHex(p),r.color.setHex(p));if(b)for(d=0;4>d;d++)p=y[k++],p=x[p],2!==d&&t.vertexColors.push(new THREE.Color(p)),0!==d&&r.vertexColors.push(new THREE.Color(p));c.faces.push(t);c.faces.push(r)}else{t=new THREE.Face3;t.a=y[k++];t.b=y[k++];t.c=y[k++];h&&(h=y[k++],t.materialIndex=h);h=c.faces.length;if(d)for(d=0;dg;g++)m=y[k++],v=u[2*m],m=u[2*m+1], -v=new THREE.Vector2(v,m),c.faceVertexUvs[d][h].push(v);q&&(q=3*y[k++],t.normal.set(C[q++],C[q++],C[q]));if(s)for(d=0;3>d;d++)q=3*y[k++],s=new THREE.Vector3(C[q++],C[q++],C[q]),t.vertexNormals.push(s);p&&(p=y[k++],t.color.setHex(x[p]));if(b)for(d=0;3>d;d++)p=y[k++],t.vertexColors.push(new THREE.Color(x[p]));c.faces.push(t)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,g=a.skinWeights.length;dg;g++)n=x[k++],v=u[2*n],n=u[2*n+1],v=new THREE.Vector2(v,n),2!==g&&c.faceVertexUvs[d][h].push(v),0!==g&&c.faceVertexUvs[d][h+1].push(v);q&&(q=3*x[k++],t.normal.set(D[q++],D[q++],D[q]),s.normal.copy(t.normal));if(r)for(d=0;4>d;d++)q=3*x[k++],r=new THREE.Vector3(D[q++], +D[q++],D[q]),2!==d&&t.vertexNormals.push(r),0!==d&&s.vertexNormals.push(r);p&&(p=x[k++],p=w[p],t.color.setHex(p),s.color.setHex(p));if(b)for(d=0;4>d;d++)p=x[k++],p=w[p],2!==d&&t.vertexColors.push(new THREE.Color(p)),0!==d&&s.vertexColors.push(new THREE.Color(p));c.faces.push(t);c.faces.push(s)}else{t=new THREE.Face3;t.a=x[k++];t.b=x[k++];t.c=x[k++];h&&(h=x[k++],t.materialIndex=h);h=c.faces.length;if(d)for(d=0;dg;g++)n=x[k++],v=u[2*n],n=u[2*n+1], +v=new THREE.Vector2(v,n),c.faceVertexUvs[d][h].push(v);q&&(q=3*x[k++],t.normal.set(D[q++],D[q++],D[q]));if(r)for(d=0;3>d;d++)q=3*x[k++],r=new THREE.Vector3(D[q++],D[q++],D[q]),t.vertexNormals.push(r);p&&(p=x[k++],t.color.setHex(w[p]));if(b)for(d=0;3>d;d++)p=x[k++],t.vertexColors.push(new THREE.Color(w[p]));c.faces.push(t)}})(d);(function(){var b=void 0!==a.influencesPerVertex?a.influencesPerVertex:2;if(a.skinWeights)for(var d=0,g=a.skinWeights.length;dthis.opacity&&(a.opacity=this.opacity);!1!== -this.transparent&&(a.transparent=this.transparent);!1!==this.wireframe&&(a.wireframe=this.wireframe);return a},clone:function(a){void 0===a&&(a=new THREE.Material);a.name=this.name;a.side=this.side;a.opacity=this.opacity;a.transparent=this.transparent;a.blending=this.blending;a.blendSrc=this.blendSrc;a.blendDst=this.blendDst;a.blendEquation=this.blendEquation;a.blendSrcAlpha=this.blendSrcAlpha;a.blendDstAlpha=this.blendDstAlpha;a.blendEquationAlpha=this.blendEquationAlpha;a.depthTest=this.depthTest; -a.depthWrite=this.depthWrite;a.polygonOffset=this.polygonOffset;a.polygonOffsetFactor=this.polygonOffsetFactor;a.polygonOffsetUnits=this.polygonOffsetUnits;a.alphaTest=this.alphaTest;a.overdraw=this.overdraw;a.visible=this.visible;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Material.prototype);THREE.MaterialIdCount=0; +THREE.CompressedTextureLoader.prototype={constructor:THREE.CompressedTextureLoader,load:function(a,b,c){var d=this,e=[],f=new THREE.CompressedTexture;f.image=e;var g=new THREE.XHRLoader;g.setResponseType("arraybuffer");if(a instanceof Array){var h=0;c=function(c){g.load(a[c],function(a){a=d._parser(a,!0);e[c]={width:a.width,height:a.height,format:a.format,mipmaps:a.mipmaps};h+=1;6===h&&(1==a.mipmapCount&&(f.minFilter=THREE.LinearFilter),f.format=a.format,f.needsUpdate=!0,b&&b(f))})};for(var k=0,l= +a.length;kthis.opacity&&(a.opacity=this.opacity);!1!==this.transparent&&(a.transparent=this.transparent);!1!==this.wireframe&& +(a.wireframe=this.wireframe);return a},clone:function(a){void 0===a&&(a=new THREE.Material);a.name=this.name;a.side=this.side;a.opacity=this.opacity;a.transparent=this.transparent;a.blending=this.blending;a.blendSrc=this.blendSrc;a.blendDst=this.blendDst;a.blendEquation=this.blendEquation;a.blendSrcAlpha=this.blendSrcAlpha;a.blendDstAlpha=this.blendDstAlpha;a.blendEquationAlpha=this.blendEquationAlpha;a.depthTest=this.depthTest;a.depthWrite=this.depthWrite;a.polygonOffset=this.polygonOffset;a.polygonOffsetFactor= +this.polygonOffsetFactor;a.polygonOffsetUnits=this.polygonOffsetUnits;a.alphaTest=this.alphaTest;a.overdraw=this.overdraw;a.visible=this.visible;return a},update:function(){this.dispatchEvent({type:"update"})},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.Material.prototype);THREE.MaterialIdCount=0; THREE.LineBasicMaterial=function(a){THREE.Material.call(this);this.type="LineBasicMaterial";this.color=new THREE.Color(16777215);this.linewidth=1;this.linejoin=this.linecap="round";this.vertexColors=THREE.NoColors;this.fog=!0;this.setValues(a)};THREE.LineBasicMaterial.prototype=Object.create(THREE.Material.prototype);THREE.LineBasicMaterial.prototype.constructor=THREE.LineBasicMaterial; THREE.LineBasicMaterial.prototype.clone=function(){var a=new THREE.LineBasicMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.linewidth=this.linewidth;a.linecap=this.linecap;a.linejoin=this.linejoin;a.vertexColors=this.vertexColors;a.fog=this.fog;return a}; THREE.LineDashedMaterial=function(a){THREE.Material.call(this);this.type="LineDashedMaterial";this.color=new THREE.Color(16777215);this.scale=this.linewidth=1;this.dashSize=3;this.gapSize=1;this.vertexColors=!1;this.fog=!0;this.setValues(a)};THREE.LineDashedMaterial.prototype=Object.create(THREE.Material.prototype);THREE.LineDashedMaterial.prototype.constructor=THREE.LineDashedMaterial; @@ -314,55 +320,55 @@ THREE.MeshPhongMaterial=function(a){THREE.Material.call(this);this.type="MeshPho THREE.MeshPhongMaterial.prototype.clone=function(){var a=new THREE.MeshPhongMaterial;THREE.Material.prototype.clone.call(this,a);a.color.copy(this.color);a.emissive.copy(this.emissive);a.specular.copy(this.specular);a.shininess=this.shininess;a.metal=this.metal;a.wrapAround=this.wrapAround;a.wrapRGB.copy(this.wrapRGB);a.map=this.map;a.lightMap=this.lightMap;a.bumpMap=this.bumpMap;a.bumpScale=this.bumpScale;a.normalMap=this.normalMap;a.normalScale.copy(this.normalScale);a.specularMap=this.specularMap; a.alphaMap=this.alphaMap;a.envMap=this.envMap;a.combine=this.combine;a.reflectivity=this.reflectivity;a.refractionRatio=this.refractionRatio;a.fog=this.fog;a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;a.wireframeLinecap=this.wireframeLinecap;a.wireframeLinejoin=this.wireframeLinejoin;a.vertexColors=this.vertexColors;a.skinning=this.skinning;a.morphTargets=this.morphTargets;a.morphNormals=this.morphNormals;return a}; THREE.MeshDepthMaterial=function(a){THREE.Material.call(this);this.type="MeshDepthMaterial";this.wireframe=this.morphTargets=!1;this.wireframeLinewidth=1;this.setValues(a)};THREE.MeshDepthMaterial.prototype=Object.create(THREE.Material.prototype);THREE.MeshDepthMaterial.prototype.constructor=THREE.MeshDepthMaterial; -THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.MeshDepthMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.type="MeshNormalMaterial";this.shading=THREE.FlatShading;this.wireframe=!1;this.wireframeLinewidth=1;this.morphTargets=!1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype); -THREE.MeshNormalMaterial.prototype.constructor=THREE.MeshNormalMaterial;THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.shading=this.shading;a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(a){this.uuid=THREE.Math.generateUUID();this.type="MeshFaceMaterial";this.materials=a instanceof Array?a:[]}; +THREE.MeshDepthMaterial.prototype.clone=function(){var a=new THREE.MeshDepthMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshNormalMaterial=function(a){THREE.Material.call(this,a);this.type="MeshNormalMaterial";this.wireframe=!1;this.wireframeLinewidth=1;this.morphTargets=!1;this.setValues(a)};THREE.MeshNormalMaterial.prototype=Object.create(THREE.Material.prototype); +THREE.MeshNormalMaterial.prototype.constructor=THREE.MeshNormalMaterial;THREE.MeshNormalMaterial.prototype.clone=function(){var a=new THREE.MeshNormalMaterial;THREE.Material.prototype.clone.call(this,a);a.wireframe=this.wireframe;a.wireframeLinewidth=this.wireframeLinewidth;return a};THREE.MeshFaceMaterial=function(a){this.uuid=THREE.Math.generateUUID();this.type="MeshFaceMaterial";this.materials=a instanceof Array?a:[]}; THREE.MeshFaceMaterial.prototype={constructor:THREE.MeshFaceMaterial,toJSON:function(){for(var a={metadata:{version:4.2,type:"material",generator:"MaterialExporter"},uuid:this.uuid,type:this.type,materials:[]},b=0,c=this.materials.length;bf||(C=b.origin.distanceTo(p),Cd.far||e.push({distance:C,point:n.clone().applyMatrix4(this.matrixWorld),index:g,offsetIndex:r,face:null,faceIndex:null, -object:this}))}}else for(m=m.position.array,g=0;gf||(C=b.origin.distanceTo(p),Cd.far||e.push({distance:C,point:n.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g instanceof THREE.Geometry)for(h=g.vertices,k=h.length,g=0;gf||(C=b.origin.distanceTo(p),Cd.far||e.push({distance:C,point:n.clone().applyMatrix4(this.matrixWorld), +THREE.Line.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere;return function(d,e){var f=d.linePrecision,f=f*f,g=this.geometry;null===g.boundingSphere&&g.computeBoundingSphere();c.copy(g.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==d.ray.isIntersectionSphere(c)){a.getInverse(this.matrixWorld);b.copy(d.ray).applyMatrix4(a);var h=new THREE.Vector3,k=new THREE.Vector3,l=new THREE.Vector3,p=new THREE.Vector3,q=this.mode===THREE.LineStrip?1:2;if(g instanceof +THREE.BufferGeometry){var n=g.attributes;if(void 0!==n.index){var t=n.index.array,n=n.position.array,r=g.offsets;0===r.length&&(r=[{start:0,count:t.length,index:0}]);for(var s=0;sf||(D=b.origin.distanceTo(p),Dd.far||e.push({distance:D,point:l.clone().applyMatrix4(this.matrixWorld),index:g,offsetIndex:s,face:null,faceIndex:null, +object:this}))}}else for(n=n.position.array,g=0;gf||(D=b.origin.distanceTo(p),Dd.far||e.push({distance:D,point:l.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g instanceof THREE.Geometry)for(h=g.vertices,k=h.length,g=0;gf||(D=b.origin.distanceTo(p),Dd.far||e.push({distance:D,point:l.clone().applyMatrix4(this.matrixWorld), index:g,face:null,faceIndex:null,object:this}))}}}();THREE.Line.prototype.clone=function(a){void 0===a&&(a=new THREE.Line(this.geometry,this.material,this.mode));THREE.Object3D.prototype.clone.call(this,a);return a};THREE.Mesh=function(a,b){THREE.Object3D.call(this);this.type="Mesh";this.geometry=void 0!==a?a:new THREE.Geometry;this.material=void 0!==b?b:new THREE.MeshBasicMaterial({color:16777215*Math.random()});this.updateMorphTargets()};THREE.Mesh.prototype=Object.create(THREE.Object3D.prototype); THREE.Mesh.prototype.constructor=THREE.Mesh;THREE.Mesh.prototype.updateMorphTargets=function(){if(void 0!==this.geometry.morphTargets&&0g.far||h.push({distance:z,point:F,face:new THREE.Face3(p,q,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this})}}}else for(r=p.position.array,s=k=0,x=r.length;k -g.far||h.push({distance:z,point:F,face:new THREE.Face3(p,q,m,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this}))}}else if(k instanceof THREE.Geometry)for(s=this.material instanceof THREE.MeshFaceMaterial,r=!0===s?this.material.materials:null,t=g.precision,u=k.vertices,v=0,y=k.faces.length;vg.far||h.push({distance:z,point:F,face:C,faceIndex:v,object:this}))}}}();THREE.Mesh.prototype.clone=function(a,b){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a,b);return a};THREE.Bone=function(a){THREE.Object3D.call(this);this.skin=a};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype);THREE.Bone.prototype.constructor=THREE.Bone; +THREE.Mesh.prototype.getMorphTargetIndexByName=function(a){if(void 0!==this.morphTargetDictionary[a])return this.morphTargetDictionary[a];THREE.warn("THREE.Mesh.getMorphTargetIndexByName: morph target "+a+" does not exist. Returning 0.");return 0}; +THREE.Mesh.prototype.raycast=function(){var a=new THREE.Matrix4,b=new THREE.Ray,c=new THREE.Sphere,d=new THREE.Vector3,e=new THREE.Vector3,f=new THREE.Vector3;return function(g,h){var k=this.geometry;null===k.boundingSphere&&k.computeBoundingSphere();c.copy(k.boundingSphere);c.applyMatrix4(this.matrixWorld);if(!1!==g.ray.isIntersectionSphere(c)&&(a.getInverse(this.matrixWorld),b.copy(g.ray).applyMatrix4(a),null===k.boundingBox||!1!==b.isIntersectionBox(k.boundingBox)))if(k instanceof THREE.BufferGeometry){var l= +this.material;if(void 0!==l){var p=k.attributes,q,n,t=g.precision;if(void 0!==p.index){var r=p.index.array,s=p.position.array,u=k.offsets;0===u.length&&(u=[{start:0,count:r.length,index:0}]);for(var v=0,x=u.length;vg.far||h.push({distance:A,point:y,face:new THREE.Face3(p,q,n,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this})}}}else for(s=p.position.array,r=k=0,w=s.length;k +g.far||h.push({distance:A,point:y,face:new THREE.Face3(p,q,n,THREE.Triangle.normal(d,e,f)),faceIndex:null,object:this}))}}else if(k instanceof THREE.Geometry)for(r=this.material instanceof THREE.MeshFaceMaterial,s=!0===r?this.material.materials:null,t=g.precision,u=k.vertices,v=0,x=k.faces.length;vg.far||h.push({distance:A,point:y,face:D,faceIndex:v,object:this}))}}}();THREE.Mesh.prototype.clone=function(a,b){void 0===a&&(a=new THREE.Mesh(this.geometry,this.material));THREE.Object3D.prototype.clone.call(this,a,b);return a};THREE.Bone=function(a){THREE.Object3D.call(this);this.type="Bone";this.skin=a};THREE.Bone.prototype=Object.create(THREE.Object3D.prototype);THREE.Bone.prototype.constructor=THREE.Bone; THREE.Skeleton=function(a,b,c){this.useVertexTexture=void 0!==c?c:!0;this.identityMatrix=new THREE.Matrix4;a=a||[];this.bones=a.slice(0);this.useVertexTexture?(this.boneTextureHeight=this.boneTextureWidth=a=256h.end&&(h.end=e);b||(b=g)}}a.firstAnimation=b}; -THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=(c.end-c.start)/b*1E3,this.time=0):console.warn("animation["+a+"] undefined")}; +THREE.MorphAnimMesh.prototype.setAnimationLabel=function(a,b,c){this.geometry.animations||(this.geometry.animations={});this.geometry.animations[a]={start:b,end:c}};THREE.MorphAnimMesh.prototype.playAnimation=function(a,b){var c=this.geometry.animations[a];c?(this.setFrameRange(c.start,c.end),this.duration=(c.end-c.start)/b*1E3,this.time=0):THREE.warn("THREE.MorphAnimMesh: animation["+a+"] undefined in .playAnimation()")}; THREE.MorphAnimMesh.prototype.updateAnimation=function(a){var b=this.duration/this.length;this.time+=this.direction*a;if(this.mirroredLoop){if(this.time>this.duration||0>this.time)this.direction*=-1,this.time>this.duration&&(this.time=this.duration,this.directionBackwards=!0),0>this.time&&(this.time=0,this.directionBackwards=!1)}else this.time%=this.duration,0>this.time&&(this.time+=this.duration);a=this.startKeyframe+THREE.Math.clamp(Math.floor(this.time/b),0,this.length-1);a!==this.currentKeyframe&& (this.morphTargetInfluences[this.lastKeyframe]=0,this.morphTargetInfluences[this.currentKeyframe]=1,this.morphTargetInfluences[a]=0,this.lastKeyframe=this.currentKeyframe,this.currentKeyframe=a);b=this.time%b/b;this.directionBackwards&&(b=1-b);this.morphTargetInfluences[this.currentKeyframe]=b;this.morphTargetInfluences[this.lastKeyframe]=1-b}; THREE.MorphAnimMesh.prototype.interpolateTargets=function(a,b,c){for(var d=this.morphTargetInfluences,e=0,f=d.length;e 0.0 ) {\n\t return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent );\n\t}\n\treturn 1.0;\n}\n\nvec3 inputToLinear( in vec3 a ) {\n#ifdef GAMMA_INPUT\n\treturn pow( a, vec3( float( GAMMA_FACTOR ) ) );\n#else\n\treturn a;\n#endif\n}\nvec3 linearToOutput( in vec3 a ) {\n#ifdef GAMMA_OUTPUT\n\treturn pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) );\n#else\n\treturn a;\n#endif\n}\n"; +THREE.ShaderChunk.alphatest_fragment="#ifdef ALPHATEST\n\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n\n#endif\n";THREE.ShaderChunk.lights_lambert_vertex="vLightFront = vec3( 0.0 );\n\n#ifdef DOUBLE_SIDED\n\n\tvLightBack = vec3( 0.0 );\n\n#endif\n\ntransformedNormal = normalize( transformedNormal );\n\n#if MAX_DIR_LIGHTS > 0\n\nfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n\tvec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n\tfloat dotProduct = dot( transformedNormal, dirVector );\n\tvec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n\t#ifdef DOUBLE_SIDED\n\n\t\tvec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n\t\t#ifdef WRAP_AROUND\n\n\t\t\tvec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n\t\t#endif\n\n\t#endif\n\n\t#ifdef WRAP_AROUND\n\n\t\tvec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n\t\tdirectionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tdirectionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );\n\n\t\t#endif\n\n\t#endif\n\n\tvLightFront += directionalLightColor[ i ] * directionalLightWeighting;\n\n\t#ifdef DOUBLE_SIDED\n\n\t\tvLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;\n\n\t#endif\n\n}\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n\t\tlVector = normalize( lVector );\n\t\tfloat dotProduct = dot( transformedNormal, lVector );\n\n\t\tvec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tvec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n\t\t\t#ifdef WRAP_AROUND\n\n\t\t\t\tvec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n\t\t\t#endif\n\n\t\t#endif\n\n\t\t#ifdef WRAP_AROUND\n\n\t\t\tvec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n\t\t\tpointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );\n\n\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\tpointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );\n\n\t\t\t#endif\n\n\t\t#endif\n\n\t\tvLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation;\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tvLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation;\n\n\t\t#endif\n\n\t}\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n\t\tvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz - mvPosition.xyz;\n\n\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );\n\n\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\n\n\t\t\tspotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n\t\t\tfloat attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n\t\t\tlVector = normalize( lVector );\n\n\t\t\tfloat dotProduct = dot( transformedNormal, lVector );\n\t\t\tvec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );\n\n\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\tvec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );\n\n\t\t\t\t#ifdef WRAP_AROUND\n\n\t\t\t\t\tvec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );\n\n\t\t\t\t#endif\n\n\t\t\t#endif\n\n\t\t\t#ifdef WRAP_AROUND\n\n\t\t\t\tvec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );\n\t\t\t\tspotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );\n\n\t\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\t\tspotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );\n\n\t\t\t\t#endif\n\n\t\t\t#endif\n\n\t\t\tvLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect;\n\n\t\t\t#ifdef DOUBLE_SIDED\n\n\t\t\t\tvLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect;\n\n\t\t\t#endif\n\n\t\t}\n\n\t}\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n\t\tvec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n\t\tfloat dotProduct = dot( transformedNormal, lVector );\n\n\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\t\tfloat hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;\n\n\t\tvLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n\t\t#ifdef DOUBLE_SIDED\n\n\t\t\tvLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );\n\n\t\t#endif\n\n\t}\n\n#endif\n\nvLightFront += ambientLightColor;\n\n#ifdef DOUBLE_SIDED\n\n\tvLightBack += ambientLightColor;\n\n#endif\n"; +THREE.ShaderChunk.map_particle_pars_fragment="#ifdef USE_MAP\n\n\tuniform vec4 offsetRepeat;\n\tuniform sampler2D map;\n\n#endif\n";THREE.ShaderChunk.default_vertex="#ifdef USE_SKINNING\n\n\tvec4 mvPosition = modelViewMatrix * skinned;\n\n#elif defined( USE_MORPHTARGETS )\n\n\tvec4 mvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n\n#else\n\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\n#endif\n\ngl_Position = projectionMatrix * mvPosition;\n"; +THREE.ShaderChunk.map_pars_fragment="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n\tvarying vec2 vUv;\n\n#endif\n\n#ifdef USE_MAP\n\n\tuniform sampler2D map;\n\n#endif";THREE.ShaderChunk.skinnormal_vertex="#ifdef USE_SKINNING\n\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\n\t#ifdef USE_MORPHNORMALS\n\n\tvec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );\n\n\t#else\n\n\tvec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );\n\n\t#endif\n\n#endif\n"; +THREE.ShaderChunk.logdepthbuf_pars_vertex="#ifdef USE_LOGDEPTHBUF\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tvarying float vFragDepth;\n\n\t#endif\n\n\tuniform float logDepthBufFC;\n\n#endif";THREE.ShaderChunk.lightmap_pars_vertex="#ifdef USE_LIGHTMAP\n\n\tvarying vec2 vUv2;\n\n#endif";THREE.ShaderChunk.lights_phong_fragment="#ifndef FLAT_SHADED\n\n\tvec3 normal = normalize( vNormal );\n\n\t#ifdef DOUBLE_SIDED\n\n\t\tnormal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\n\t#endif\n\n#else\n\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n\n#endif\n\nvec3 viewPosition = normalize( vViewPosition );\n\n#ifdef USE_NORMALMAP\n\n\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n\n#elif defined( USE_BUMPMAP )\n\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n\n#endif\n\nvec3 totalDiffuseLight = vec3( 0.0 );\nvec3 totalSpecularLight = vec3( 0.0 );\n\n#if MAX_POINT_LIGHTS > 0\n\n\tfor ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {\n\n\t\tvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] );\n\n\t\tlVector = normalize( lVector );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, lVector );\n\n\t\t#ifdef WRAP_AROUND\n\n\t\t\tfloat pointDiffuseWeightFull = max( dotProduct, 0.0 );\n\t\t\tfloat pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n\t\t\tvec3 pointDiffuseWeight = mix( vec3( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );\n\n\t\t#else\n\n\t\t\tfloat pointDiffuseWeight = max( dotProduct, 0.0 );\n\n\t\t#endif\n\n\t\ttotalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;\n\n\t\t\t\t// specular\n\n\t\tvec3 pointHalfVector = normalize( lVector + viewPosition );\n\t\tfloat pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );\n\t\tfloat pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );\n\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );\n\t\ttotalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;\n\n\t}\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tfor ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {\n\n\t\tvec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );\n\t\tvec3 lVector = lPosition.xyz + vViewPosition.xyz;\n\n\t\tfloat attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] );\n\n\t\tlVector = normalize( lVector );\n\n\t\tfloat spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );\n\n\t\tif ( spotEffect > spotLightAngleCos[ i ] ) {\n\n\t\t\tspotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );\n\n\t\t\t// diffuse\n\n\t\t\tfloat dotProduct = dot( normal, lVector );\n\n\t\t\t#ifdef WRAP_AROUND\n\n\t\t\t\tfloat spotDiffuseWeightFull = max( dotProduct, 0.0 );\n\t\t\t\tfloat spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n\t\t\t\tvec3 spotDiffuseWeight = mix( vec3( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );\n\n\t\t\t#else\n\n\t\t\t\tfloat spotDiffuseWeight = max( dotProduct, 0.0 );\n\n\t\t\t#endif\n\n\t\t\ttotalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;\n\n\t\t\t// specular\n\n\t\t\tvec3 spotHalfVector = normalize( lVector + viewPosition );\n\t\t\tfloat spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );\n\t\t\tfloat spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );\n\n\t\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n\t\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );\n\t\t\ttotalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;\n\n\t\t}\n\n\t}\n\n#endif\n\n#if MAX_DIR_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {\n\n\t\tvec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, dirVector );\n\n\t\t#ifdef WRAP_AROUND\n\n\t\t\tfloat dirDiffuseWeightFull = max( dotProduct, 0.0 );\n\t\t\tfloat dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );\n\n\t\t\tvec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );\n\n\t\t#else\n\n\t\t\tfloat dirDiffuseWeight = max( dotProduct, 0.0 );\n\n\t\t#endif\n\n\t\ttotalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;\n\n\t\t// specular\n\n\t\tvec3 dirHalfVector = normalize( dirVector + viewPosition );\n\t\tfloat dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );\n\t\tfloat dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );\n\n\t\t/*\n\t\t// fresnel term from skin shader\n\t\tconst float F0 = 0.128;\n\n\t\tfloat base = 1.0 - dot( viewPosition, dirHalfVector );\n\t\tfloat exponential = pow( base, 5.0 );\n\n\t\tfloat fresnel = exponential + F0 * ( 1.0 - exponential );\n\t\t*/\n\n\t\t/*\n\t\t// fresnel term from fresnel shader\n\t\tconst float mFresnelBias = 0.08;\n\t\tconst float mFresnelScale = 0.3;\n\t\tconst float mFresnelPower = 5.0;\n\n\t\tfloat fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );\n\t\t*/\n\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n\t\t// \t\tdirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;\n\n\t\tvec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );\n\t\ttotalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;\n\n\n\t}\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tfor( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {\n\n\t\tvec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );\n\n\t\t// diffuse\n\n\t\tfloat dotProduct = dot( normal, lVector );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotProduct + 0.5;\n\n\t\tvec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );\n\n\t\ttotalDiffuseLight += hemiColor;\n\n\t\t// specular (sky light)\n\n\t\tvec3 hemiHalfVectorSky = normalize( lVector + viewPosition );\n\t\tfloat hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;\n\t\tfloat hemiSpecularWeightSky = specularStrength * max( pow( max( hemiDotNormalHalfSky, 0.0 ), shininess ), 0.0 );\n\n\t\t// specular (ground light)\n\n\t\tvec3 lVectorGround = -lVector;\n\n\t\tvec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );\n\t\tfloat hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;\n\t\tfloat hemiSpecularWeightGround = specularStrength * max( pow( max( hemiDotNormalHalfGround, 0.0 ), shininess ), 0.0 );\n\n\t\tfloat dotProductGround = dot( normal, lVectorGround );\n\n\t\tfloat specularNormalization = ( shininess + 2.0 ) / 8.0;\n\n\t\tvec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );\n\t\tvec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );\n\t\ttotalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );\n\n\t}\n\n#endif\n\n#ifdef METAL\n\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;\n\n#else\n\n\toutgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;\n\n#endif\n"; THREE.ShaderChunk.fog_pars_fragment="#ifdef USE_FOG\n\n\tuniform vec3 fogColor;\n\n\t#ifdef FOG_EXP2\n\n\t\tuniform float fogDensity;\n\n\t#else\n\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n\n#endif";THREE.ShaderChunk.morphnormal_vertex="#ifdef USE_MORPHNORMALS\n\n\tvec3 morphedNormal = vec3( 0.0 );\n\n\tmorphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tmorphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tmorphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tmorphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n\n\tmorphedNormal += normal;\n\n#endif"; THREE.ShaderChunk.envmap_pars_fragment="#ifdef USE_ENVMAP\n\n\tuniform float reflectivity;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n\t\tuniform float refractionRatio;\n\n\t#else\n\n\t\tvarying vec3 vReflect;\n\n\t#endif\n\n#endif\n";THREE.ShaderChunk.logdepthbuf_fragment="#if defined(USE_LOGDEPTHBUF) && defined(USE_LOGDEPTHBUF_EXT)\n\n\tgl_FragDepthEXT = log2(vFragDepth) * logDepthBufFC * 0.5;\n\n#endif"; -THREE.ShaderChunk.normalmap_pars_fragment="#ifdef USE_NORMALMAP\n\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\n\t\t\t// Per-Pixel Tangent Space Normal Mapping\n\t\t\t// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\n\t}\n\n#endif\n"; +THREE.ShaderChunk.normalmap_pars_fragment="#ifdef USE_NORMALMAP\n\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\n\t// Per-Pixel Tangent Space Normal Mapping\n\t// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html\n\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\n\t\tvec3 S = normalize( q0 * st1.t - q1 * st0.t );\n\t\tvec3 T = normalize( -q0 * st1.s + q1 * st0.s );\n\t\tvec3 N = normalize( surf_norm );\n\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\n\t}\n\n#endif\n"; THREE.ShaderChunk.lights_phong_pars_vertex="#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n\tvarying vec3 vWorldPosition;\n\n#endif\n";THREE.ShaderChunk.lightmap_pars_fragment="#ifdef USE_LIGHTMAP\n\n\tvarying vec2 vUv2;\n\tuniform sampler2D lightMap;\n\n#endif";THREE.ShaderChunk.shadowmap_vertex="#ifdef USE_SHADOWMAP\n\n\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n\t\tvShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;\n\n\t}\n\n#endif"; -THREE.ShaderChunk.lights_phong_vertex="#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n\tvWorldPosition = worldPosition.xyz;\n\n#endif";THREE.ShaderChunk.map_fragment="#ifdef USE_MAP\n\n\tvec4 texelColor = texture2D( map, vUv );\n\n\t#ifdef GAMMA_INPUT\n\n\t\ttexelColor.xyz *= texelColor.xyz;\n\n\t#endif\n\n\tgl_FragColor = gl_FragColor * texelColor;\n\n#endif";THREE.ShaderChunk.lightmap_vertex="#ifdef USE_LIGHTMAP\n\n\tvUv2 = uv2;\n\n#endif"; -THREE.ShaderChunk.map_particle_fragment="#ifdef USE_MAP\n\n\tgl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );\n\n#endif";THREE.ShaderChunk.color_pars_fragment="#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif\n";THREE.ShaderChunk.color_vertex="#ifdef USE_COLOR\n\n\t#ifdef GAMMA_INPUT\n\n\t\tvColor = square( color );\n\n\t#else\n\n\t\tvColor = color;\n\n\t#endif\n\n#endif";THREE.ShaderChunk.skinning_vertex="#ifdef USE_SKINNING\n\n\t#ifdef USE_MORPHTARGETS\n\n\tvec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );\n\n\t#else\n\n\tvec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\n\t#endif\n\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned = bindMatrixInverse * skinned;\n\n#endif\n"; -THREE.ShaderChunk.envmap_pars_vertex="#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n\tvarying vec3 vReflect;\n\n\tuniform float refractionRatio;\n\n#endif\n";THREE.ShaderChunk.linear_to_gamma_fragment="#ifdef GAMMA_OUTPUT\n\n\tgl_FragColor.xyz = sqrt( gl_FragColor.xyz );\n\n#endif";THREE.ShaderChunk.color_pars_vertex="#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif";THREE.ShaderChunk.lights_lambert_pars_vertex="uniform vec3 diffuse;\nuniform vec3 emissive;\n\nuniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n\tuniform vec3 wrapRGB;\n\n#endif\n"; -THREE.ShaderChunk.map_pars_vertex="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n\n#endif\n";THREE.ShaderChunk.envmap_fragment="#ifdef USE_ENVMAP\n\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n\t\t// Transforming Normal Vectors with the Inverse Transformation\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n\t\t#else\n\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n\t\t#endif\n\n\t#else\n\n\t\tvec3 reflectVec = vReflect;\n\n\t#endif\n\n\t#ifdef DOUBLE_SIDED\n\t\tfloat flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\t#else\n\t\tfloat flipNormal = 1.0;\n\t#endif\n\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t\t\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#endif\n\n\t#ifdef GAMMA_INPUT\n\n\t\tenvColor.xyz *= envColor.xyz;\n\n\t#endif\n\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\n\t\tgl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * envColor.xyz, specularStrength * reflectivity );\n\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\n\t\tgl_FragColor.xyz = mix( gl_FragColor.xyz, envColor.xyz, specularStrength * reflectivity );\n\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\n\t\tgl_FragColor.xyz += envColor.xyz * specularStrength * reflectivity;\n\n\t#endif\n\n#endif\n"; +THREE.ShaderChunk.lights_phong_vertex="#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n\tvWorldPosition = worldPosition.xyz;\n\n#endif";THREE.ShaderChunk.map_fragment="#ifdef USE_MAP\n\n\tvec4 texelColor = texture2D( map, vUv );\n\n\ttexelColor.xyz = inputToLinear( texelColor.xyz );\n\n\tdiffuseColor *= texelColor;\n\n#endif";THREE.ShaderChunk.lightmap_vertex="#ifdef USE_LIGHTMAP\n\n\tvUv2 = uv2;\n\n#endif";THREE.ShaderChunk.map_particle_fragment="#ifdef USE_MAP\n\n\tdiffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );\n\n#endif\n"; +THREE.ShaderChunk.color_pars_fragment="#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif\n";THREE.ShaderChunk.color_vertex="#ifdef USE_COLOR\n\n\tvColor.xyz = inputToLinear( color.xyz );\n\n#endif";THREE.ShaderChunk.skinning_vertex="#ifdef USE_SKINNING\n\n\t#ifdef USE_MORPHTARGETS\n\n\tvec4 skinVertex = bindMatrix * vec4( morphed, 1.0 );\n\n\t#else\n\n\tvec4 skinVertex = bindMatrix * vec4( position, 1.0 );\n\n\t#endif\n\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\tskinned = bindMatrixInverse * skinned;\n\n#endif\n"; +THREE.ShaderChunk.envmap_pars_vertex="#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n\tvarying vec3 vReflect;\n\n\tuniform float refractionRatio;\n\n#endif\n";THREE.ShaderChunk.linear_to_gamma_fragment="\n\toutgoingLight = linearToOutput( outgoingLight );\n";THREE.ShaderChunk.color_pars_vertex="#ifdef USE_COLOR\n\n\tvarying vec3 vColor;\n\n#endif";THREE.ShaderChunk.lights_lambert_pars_vertex="uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#ifdef WRAP_AROUND\n\n\tuniform vec3 wrapRGB;\n\n#endif\n"; +THREE.ShaderChunk.map_pars_vertex="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n\tvarying vec2 vUv;\n\tuniform vec4 offsetRepeat;\n\n#endif\n";THREE.ShaderChunk.envmap_fragment="#ifdef USE_ENVMAP\n\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n\t\t// Transforming Normal Vectors with the Inverse Transformation\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\n\t\t#else\n\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n\t\t#endif\n\n\t#else\n\n\t\tvec3 reflectVec = vReflect;\n\n\t#endif\n\n\t#ifdef DOUBLE_SIDED\n\t\tfloat flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n\t#else\n\t\tfloat flipNormal = 1.0;\n\t#endif\n\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\tsampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );\n\t\tsampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\tvec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#endif\n\n\tenvColor.xyz = inputToLinear( envColor.xyz );\n\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\n\t#endif\n\n#endif\n"; THREE.ShaderChunk.specularmap_pars_fragment="#ifdef USE_SPECULARMAP\n\n\tuniform sampler2D specularMap;\n\n#endif";THREE.ShaderChunk.logdepthbuf_vertex="#ifdef USE_LOGDEPTHBUF\n\n\tgl_Position.z = log2(max( EPSILON, gl_Position.w + 1.0 )) * logDepthBufFC;\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\n#else\n\n\t\tgl_Position.z = (gl_Position.z - 1.0) * gl_Position.w;\n\n\t#endif\n\n#endif";THREE.ShaderChunk.morphtarget_pars_vertex="#ifdef USE_MORPHTARGETS\n\n\t#ifndef USE_MORPHNORMALS\n\n\tuniform float morphTargetInfluences[ 8 ];\n\n\t#else\n\n\tuniform float morphTargetInfluences[ 4 ];\n\n\t#endif\n\n#endif"; -THREE.ShaderChunk.specularmap_fragment="float specularStrength;\n\n#ifdef USE_SPECULARMAP\n\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n\n#else\n\n\tspecularStrength = 1.0;\n\n#endif";THREE.ShaderChunk.fog_fragment="#ifdef USE_FOG\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n\t#else\n\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\n\t#endif\n\n\t#ifdef FOG_EXP2\n\n\t\tfloat fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n\t\tfogFactor = whiteCompliment( fogFactor );\n\n\t#else\n\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n\n\t#endif\n\t\n\tgl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n\n#endif"; -THREE.ShaderChunk.bumpmap_pars_fragment="#ifdef USE_BUMPMAP\n\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\n\t\t\t// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n\t\t\t//\thttp://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n\t\t\t// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n\tvec2 dHdxy_fwd() {\n\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n\t\treturn vec2( dBx, dBy );\n\n\t}\n\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\t\t// normalized\n\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\n\t}\n\n#endif"; -THREE.ShaderChunk.defaultnormal_vertex="#ifdef USE_SKINNING\n\n\tvec3 objectNormal = skinnedNormal.xyz;\n\n#elif defined( USE_MORPHNORMALS )\n\n\tvec3 objectNormal = morphedNormal;\n\n#else\n\n\tvec3 objectNormal = normal;\n\n#endif\n\n#ifdef FLIP_SIDED\n\n\tobjectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n";THREE.ShaderChunk.lights_phong_pars_fragment="uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n\tvarying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n\tuniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;"; +THREE.ShaderChunk.specularmap_fragment="float specularStrength;\n\n#ifdef USE_SPECULARMAP\n\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n\n#else\n\n\tspecularStrength = 1.0;\n\n#endif";THREE.ShaderChunk.fog_fragment="#ifdef USE_FOG\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\n\t#else\n\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\n\t#endif\n\n\t#ifdef FOG_EXP2\n\n\t\tfloat fogFactor = exp2( - square( fogDensity ) * square( depth ) * LOG2 );\n\t\tfogFactor = whiteCompliment( fogFactor );\n\n\t#else\n\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n\n\t#endif\n\t\n\toutgoingLight = mix( outgoingLight, fogColor, fogFactor );\n\n#endif"; +THREE.ShaderChunk.bumpmap_pars_fragment="#ifdef USE_BUMPMAP\n\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\n\t// Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen\n\t// http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html\n\n\t// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)\n\n\tvec2 dHdxy_fwd() {\n\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\n\t\treturn vec2( dBx, dBy );\n\n\t}\n\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\n\t\tvec3 vSigmaX = dFdx( surf_pos );\n\t\tvec3 vSigmaY = dFdy( surf_pos );\n\t\tvec3 vN = surf_norm;\t\t// normalized\n\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\n\t}\n\n#endif\n"; +THREE.ShaderChunk.defaultnormal_vertex="#ifdef USE_SKINNING\n\n\tvec3 objectNormal = skinnedNormal.xyz;\n\n#elif defined( USE_MORPHNORMALS )\n\n\tvec3 objectNormal = morphedNormal;\n\n#else\n\n\tvec3 objectNormal = normal;\n\n#endif\n\n#ifdef FLIP_SIDED\n\n\tobjectNormal = -objectNormal;\n\n#endif\n\nvec3 transformedNormal = normalMatrix * objectNormal;\n";THREE.ShaderChunk.lights_phong_pars_fragment="uniform vec3 ambientLightColor;\n\n#if MAX_DIR_LIGHTS > 0\n\n\tuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\n\tuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n\n#endif\n\n#if MAX_HEMI_LIGHTS > 0\n\n\tuniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];\n\tuniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];\n\n#endif\n\n#if MAX_POINT_LIGHTS > 0\n\n\tuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\n\n\tuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDistance[ MAX_POINT_LIGHTS ];\n\tuniform float pointLightDecay[ MAX_POINT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0\n\n\tuniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];\n\tuniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightExponent[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDistance[ MAX_SPOT_LIGHTS ];\n\tuniform float spotLightDecay[ MAX_SPOT_LIGHTS ];\n\n#endif\n\n#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP ) || defined( USE_ENVMAP )\n\n\tvarying vec3 vWorldPosition;\n\n#endif\n\n#ifdef WRAP_AROUND\n\n\tuniform vec3 wrapRGB;\n\n#endif\n\nvarying vec3 vViewPosition;\n\n#ifndef FLAT_SHADED\n\n\tvarying vec3 vNormal;\n\n#endif\n"; THREE.ShaderChunk.skinbase_vertex="#ifdef USE_SKINNING\n\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n\n#endif";THREE.ShaderChunk.map_vertex="#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP )\n\n\tvUv = uv * offsetRepeat.zw + offsetRepeat.xy;\n\n#endif"; -THREE.ShaderChunk.lightmap_fragment="#ifdef USE_LIGHTMAP\n\n\tgl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );\n\n#endif";THREE.ShaderChunk.shadowmap_pars_vertex="#ifdef USE_SHADOWMAP\n\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\n\tuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n\n#endif";THREE.ShaderChunk.color_fragment="#ifdef USE_COLOR\n\n\tgl_FragColor = gl_FragColor * vec4( vColor, 1.0 );\n\n#endif";THREE.ShaderChunk.morphtarget_vertex="#ifdef USE_MORPHTARGETS\n\n\tvec3 morphed = vec3( 0.0 );\n\tmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\tmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\tmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\tmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n\t#ifndef USE_MORPHNORMALS\n\n\tmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\tmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\tmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\tmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n\t#endif\n\n\tmorphed += position;\n\n#endif"; +THREE.ShaderChunk.lightmap_fragment="#ifdef USE_LIGHTMAP\n\n\toutgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;\n\n#endif";THREE.ShaderChunk.shadowmap_pars_vertex="#ifdef USE_SHADOWMAP\n\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\n\tuniform mat4 shadowMatrix[ MAX_SHADOWS ];\n\n#endif";THREE.ShaderChunk.color_fragment="#ifdef USE_COLOR\n\n\tdiffuseColor.rgb *= vColor;\n\n#endif";THREE.ShaderChunk.morphtarget_vertex="#ifdef USE_MORPHTARGETS\n\n\tvec3 morphed = vec3( 0.0 );\n\tmorphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\tmorphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\tmorphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\tmorphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n\t#ifndef USE_MORPHNORMALS\n\n\tmorphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\tmorphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\tmorphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\tmorphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n\t#endif\n\n\tmorphed += position;\n\n#endif"; THREE.ShaderChunk.envmap_vertex="#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n\tvec3 worldNormal = transformDirection( objectNormal, modelMatrix );\n\n\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n\t#ifdef ENVMAP_MODE_REFLECTION\n\n\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\n\t#else\n\n\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n\t#endif\n\n#endif\n"; -THREE.ShaderChunk.shadowmap_fragment="#ifdef USE_SHADOWMAP\n\n\t#ifdef SHADOWMAP_DEBUG\n\n\t\tvec3 frustumColors[3];\n\t\tfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n\t\tfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n\t\tfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n\t#endif\n\n\t#ifdef SHADOWMAP_CASCADE\n\n\t\tint inFrustumCount = 0;\n\n\t#endif\n\n\tfloat fDepth;\n\tvec3 shadowColor = vec3( 1.0 );\n\n\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n\t\tvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n\t\t\t\t// if ( something && something ) breaks ATI OpenGL shader compiler\n\t\t\t\t// if ( all( something, something ) ) using this instead\n\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\n\t\t\t\t// don't shadow pixels outside of light frustum\n\t\t\t\t// use just first frustum (for cascades)\n\t\t\t\t// don't shadow pixels behind far plane of light frustum\n\n\t\t#ifdef SHADOWMAP_CASCADE\n\n\t\t\tinFrustumCount += int( inFrustum );\n\t\t\tbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n\t\t#else\n\n\t\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n\t\t#endif\n\n\t\tbool frustumTest = all( frustumTestVec );\n\n\t\tif ( frustumTest ) {\n\n\t\t\tshadowCoord.z += shadowBias[ i ];\n\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\n\t\t\t\t\t\t// Percentage-close filtering\n\t\t\t\t\t\t// (9 pixel kernel)\n\t\t\t\t\t\t// http://fabiensanglard.net/shadowmappingPCF/\n\n\t\t\t\tfloat shadow = 0.0;\n\n\t\t/*\n\t\t\t\t\t\t// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n\t\t\t\t\t\t// must enroll loop manually\n\n\t\t\t\tfor ( float y = -1.25; y <= 1.25; y += 1.25 )\n\t\t\t\t\tfor ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n\t\t\t\t\t\tvec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n\t\t\t\t\t\t\t\t// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n\t\t\t\t\t\t\t\t//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n\t\t\t\t\t\tfloat fDepth = unpackDepth( rgbaDepth );\n\n\t\t\t\t\t\tif ( fDepth < shadowCoord.z )\n\t\t\t\t\t\t\tshadow += 1.0;\n\n\t\t\t\t}\n\n\t\t\t\tshadow /= 9.0;\n\n\t\t*/\n\n\t\t\t\tconst float shadowDelta = 1.0 / 9.0;\n\n\t\t\t\tfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n\t\t\t\tfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n\t\t\t\tfloat dx0 = -1.25 * xPixelOffset;\n\t\t\t\tfloat dy0 = -1.25 * yPixelOffset;\n\t\t\t\tfloat dx1 = 1.25 * xPixelOffset;\n\t\t\t\tfloat dy1 = 1.25 * yPixelOffset;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n\t\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n\t\t\t\t\t\t// Percentage-close filtering\n\t\t\t\t\t\t// (9 pixel kernel)\n\t\t\t\t\t\t// http://fabiensanglard.net/shadowmappingPCF/\n\n\t\t\t\tfloat shadow = 0.0;\n\n\t\t\t\tfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n\t\t\t\tfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n\t\t\t\tfloat dx0 = -1.0 * xPixelOffset;\n\t\t\t\tfloat dy0 = -1.0 * yPixelOffset;\n\t\t\t\tfloat dx1 = 1.0 * xPixelOffset;\n\t\t\t\tfloat dy1 = 1.0 * yPixelOffset;\n\n\t\t\t\tmat3 shadowKernel;\n\t\t\t\tmat3 depthKernel;\n\n\t\t\t\tdepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n\t\t\t\tdepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n\t\t\t\tdepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n\t\t\t\tdepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n\t\t\t\tdepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n\t\t\t\tdepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n\t\t\t\tdepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n\t\t\t\tdepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n\t\t\t\tdepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n\t\t\t\tvec3 shadowZ = vec3( shadowCoord.z );\n\t\t\t\tshadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n\t\t\t\tshadowKernel[0] *= vec3(0.25);\n\n\t\t\t\tshadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n\t\t\t\tshadowKernel[1] *= vec3(0.25);\n\n\t\t\t\tshadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n\t\t\t\tshadowKernel[2] *= vec3(0.25);\n\n\t\t\t\tvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n\t\t\t\tshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n\t\t\t\tshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n\t\t\t\tvec4 shadowValues;\n\t\t\t\tshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n\t\t\t\tshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n\t\t\t\tshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n\t\t\t\tshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n\t\t\t\tshadow = dot( shadowValues, vec4( 1.0 ) );\n\n\t\t\t\tshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n\t\t\t#else\n\n\t\t\t\tvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n\t\t\t\tfloat fDepth = unpackDepth( rgbaDepth );\n\n\t\t\t\tif ( fDepth < shadowCoord.z )\n\n\t\t// spot with multiple shadows is darker\n\n\t\t\t\t\tshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n\t\t// spot with multiple shadows has the same color as single shadow spot\n\n\t\t// \t\t\t\t\tshadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n\t\t\t#endif\n\n\t\t}\n\n\n\t\t#ifdef SHADOWMAP_DEBUG\n\n\t\t\t#ifdef SHADOWMAP_CASCADE\n\n\t\t\t\tif ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];\n\n\t\t\t#else\n\n\t\t\t\tif ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];\n\n\t\t\t#endif\n\n\t\t#endif\n\n\t}\n\n\t#ifdef GAMMA_OUTPUT\n\n\t\tshadowColor *= shadowColor;\n\n\t#endif\n\n\tgl_FragColor.xyz = gl_FragColor.xyz * shadowColor;\n\n#endif\n"; +THREE.ShaderChunk.shadowmap_fragment="#ifdef USE_SHADOWMAP\n\n\t#ifdef SHADOWMAP_DEBUG\n\n\t\tvec3 frustumColors[3];\n\t\tfrustumColors[0] = vec3( 1.0, 0.5, 0.0 );\n\t\tfrustumColors[1] = vec3( 0.0, 1.0, 0.8 );\n\t\tfrustumColors[2] = vec3( 0.0, 0.5, 1.0 );\n\n\t#endif\n\n\t#ifdef SHADOWMAP_CASCADE\n\n\t\tint inFrustumCount = 0;\n\n\t#endif\n\n\tfloat fDepth;\n\tvec3 shadowColor = vec3( 1.0 );\n\n\tfor( int i = 0; i < MAX_SHADOWS; i ++ ) {\n\n\t\tvec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;\n\n\t\t\t\t// if ( something && something ) breaks ATI OpenGL shader compiler\n\t\t\t\t// if ( all( something, something ) ) using this instead\n\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\n\t\t\t\t// don't shadow pixels outside of light frustum\n\t\t\t\t// use just first frustum (for cascades)\n\t\t\t\t// don't shadow pixels behind far plane of light frustum\n\n\t\t#ifdef SHADOWMAP_CASCADE\n\n\t\t\tinFrustumCount += int( inFrustum );\n\t\t\tbvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );\n\n\t\t#else\n\n\t\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\n\t\t#endif\n\n\t\tbool frustumTest = all( frustumTestVec );\n\n\t\tif ( frustumTest ) {\n\n\t\t\tshadowCoord.z += shadowBias[ i ];\n\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\n\t\t\t\t\t\t// Percentage-close filtering\n\t\t\t\t\t\t// (9 pixel kernel)\n\t\t\t\t\t\t// http://fabiensanglard.net/shadowmappingPCF/\n\n\t\t\t\tfloat shadow = 0.0;\n\n\t\t/*\n\t\t\t\t\t\t// nested loops breaks shader compiler / validator on some ATI cards when using OpenGL\n\t\t\t\t\t\t// must enroll loop manually\n\n\t\t\t\tfor ( float y = -1.25; y <= 1.25; y += 1.25 )\n\t\t\t\t\tfor ( float x = -1.25; x <= 1.25; x += 1.25 ) {\n\n\t\t\t\t\t\tvec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );\n\n\t\t\t\t\t\t\t\t// doesn't seem to produce any noticeable visual difference compared to simple texture2D lookup\n\t\t\t\t\t\t\t\t//vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );\n\n\t\t\t\t\t\tfloat fDepth = unpackDepth( rgbaDepth );\n\n\t\t\t\t\t\tif ( fDepth < shadowCoord.z )\n\t\t\t\t\t\t\tshadow += 1.0;\n\n\t\t\t\t}\n\n\t\t\t\tshadow /= 9.0;\n\n\t\t*/\n\n\t\t\t\tconst float shadowDelta = 1.0 / 9.0;\n\n\t\t\t\tfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n\t\t\t\tfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n\t\t\t\tfloat dx0 = -1.25 * xPixelOffset;\n\t\t\t\tfloat dy0 = -1.25 * yPixelOffset;\n\t\t\t\tfloat dx1 = 1.25 * xPixelOffset;\n\t\t\t\tfloat dy1 = 1.25 * yPixelOffset;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tfDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\t\t\t\tif ( fDepth < shadowCoord.z ) shadow += shadowDelta;\n\n\t\t\t\tshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n\t\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\n\t\t\t\t\t\t// Percentage-close filtering\n\t\t\t\t\t\t// (9 pixel kernel)\n\t\t\t\t\t\t// http://fabiensanglard.net/shadowmappingPCF/\n\n\t\t\t\tfloat shadow = 0.0;\n\n\t\t\t\tfloat xPixelOffset = 1.0 / shadowMapSize[ i ].x;\n\t\t\t\tfloat yPixelOffset = 1.0 / shadowMapSize[ i ].y;\n\n\t\t\t\tfloat dx0 = -1.0 * xPixelOffset;\n\t\t\t\tfloat dy0 = -1.0 * yPixelOffset;\n\t\t\t\tfloat dx1 = 1.0 * xPixelOffset;\n\t\t\t\tfloat dy1 = 1.0 * yPixelOffset;\n\n\t\t\t\tmat3 shadowKernel;\n\t\t\t\tmat3 depthKernel;\n\n\t\t\t\tdepthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );\n\t\t\t\tdepthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );\n\t\t\t\tdepthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );\n\t\t\t\tdepthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );\n\t\t\t\tdepthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );\n\t\t\t\tdepthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );\n\t\t\t\tdepthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );\n\t\t\t\tdepthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );\n\t\t\t\tdepthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );\n\n\t\t\t\tvec3 shadowZ = vec3( shadowCoord.z );\n\t\t\t\tshadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));\n\t\t\t\tshadowKernel[0] *= vec3(0.25);\n\n\t\t\t\tshadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));\n\t\t\t\tshadowKernel[1] *= vec3(0.25);\n\n\t\t\t\tshadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));\n\t\t\t\tshadowKernel[2] *= vec3(0.25);\n\n\t\t\t\tvec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );\n\n\t\t\t\tshadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );\n\t\t\t\tshadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );\n\n\t\t\t\tvec4 shadowValues;\n\t\t\t\tshadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );\n\t\t\t\tshadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );\n\t\t\t\tshadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );\n\t\t\t\tshadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );\n\n\t\t\t\tshadow = dot( shadowValues, vec4( 1.0 ) );\n\n\t\t\t\tshadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );\n\n\t\t\t#else\n\n\t\t\t\tvec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );\n\t\t\t\tfloat fDepth = unpackDepth( rgbaDepth );\n\n\t\t\t\tif ( fDepth < shadowCoord.z )\n\n\t\t// spot with multiple shadows is darker\n\n\t\t\t\t\tshadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );\n\n\t\t// spot with multiple shadows has the same color as single shadow spot\n\n\t\t// \t\t\t\t\tshadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );\n\n\t\t\t#endif\n\n\t\t}\n\n\n\t\t#ifdef SHADOWMAP_DEBUG\n\n\t\t\t#ifdef SHADOWMAP_CASCADE\n\n\t\t\t\tif ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];\n\n\t\t\t#else\n\n\t\t\t\tif ( inFrustum ) outgoingLight *= frustumColors[ i ];\n\n\t\t\t#endif\n\n\t\t#endif\n\n\t}\n\n\t// NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014\n\tshadowColor = inputToLinear( shadowColor );\n\n\toutgoingLight = outgoingLight * shadowColor;\n\n#endif\n"; THREE.ShaderChunk.worldpos_vertex="#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )\n\n\t#ifdef USE_SKINNING\n\n\t\tvec4 worldPosition = modelMatrix * skinned;\n\n\t#elif defined( USE_MORPHTARGETS )\n\n\t\tvec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n\n\t#else\n\n\t\tvec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n\n\t#endif\n\n#endif\n";THREE.ShaderChunk.shadowmap_pars_fragment="#ifdef USE_SHADOWMAP\n\n\tuniform sampler2D shadowMap[ MAX_SHADOWS ];\n\tuniform vec2 shadowMapSize[ MAX_SHADOWS ];\n\n\tuniform float shadowDarkness[ MAX_SHADOWS ];\n\tuniform float shadowBias[ MAX_SHADOWS ];\n\n\tvarying vec4 vShadowCoord[ MAX_SHADOWS ];\n\n\tfloat unpackDepth( const in vec4 rgba_depth ) {\n\n\t\tconst vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );\n\t\tfloat depth = dot( rgba_depth, bit_shift );\n\t\treturn depth;\n\n\t}\n\n#endif"; THREE.ShaderChunk.skinning_pars_vertex="#ifdef USE_SKINNING\n\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\n\t#ifdef BONE_TEXTURE\n\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureWidth;\n\t\tuniform int boneTextureHeight;\n\n\t\tmat4 getBoneMatrix( const in float i ) {\n\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureWidth ) );\n\t\t\tfloat y = floor( j / float( boneTextureWidth ) );\n\n\t\t\tfloat dx = 1.0 / float( boneTextureWidth );\n\t\t\tfloat dy = 1.0 / float( boneTextureHeight );\n\n\t\t\ty = dy * ( y + 0.5 );\n\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\n\t\t\treturn bone;\n\n\t\t}\n\n\t#else\n\n\t\tuniform mat4 boneGlobalMatrices[ MAX_BONES ];\n\n\t\tmat4 getBoneMatrix( const in float i ) {\n\n\t\t\tmat4 bone = boneGlobalMatrices[ int(i) ];\n\t\t\treturn bone;\n\n\t\t}\n\n\t#endif\n\n#endif\n"; -THREE.ShaderChunk.logdepthbuf_pars_fragment="#ifdef USE_LOGDEPTHBUF\n\n\tuniform float logDepthBufFC;\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\t#extension GL_EXT_frag_depth : enable\n\t\tvarying float vFragDepth;\n\n\t#endif\n\n#endif";THREE.ShaderChunk.alphamap_fragment="#ifdef USE_ALPHAMAP\n\n\tgl_FragColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n";THREE.ShaderChunk.alphamap_pars_fragment="#ifdef USE_ALPHAMAP\n\n\tuniform sampler2D alphaMap;\n\n#endif\n"; +THREE.ShaderChunk.logdepthbuf_pars_fragment="#ifdef USE_LOGDEPTHBUF\n\n\tuniform float logDepthBufFC;\n\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\n\t\t#extension GL_EXT_frag_depth : enable\n\t\tvarying float vFragDepth;\n\n\t#endif\n\n#endif";THREE.ShaderChunk.alphamap_fragment="#ifdef USE_ALPHAMAP\n\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n\n#endif\n";THREE.ShaderChunk.alphamap_pars_fragment="#ifdef USE_ALPHAMAP\n\n\tuniform sampler2D alphaMap;\n\n#endif\n"; THREE.UniformsUtils={merge:function(a){for(var b={},c=0;c dashSize ) {\n\t\tdiscard;\n\t}\n\tgl_FragColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment, -THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.fog_fragment,"}"].join("\n")},depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f",value:1}},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float mNear;\nuniform float mFar;\nuniform float opacity;", -THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {",THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\t#else\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\t#endif\n\tfloat color = 1.0 - smoothstep( mNear, mFar, depth );\n\tgl_FragColor = vec4( vec3( color ), opacity );\n}"].join("\n")},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",THREE.ShaderChunk.common, -THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvNormal = normalize( normalMatrix * normal );",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vNormal;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",THREE.ShaderChunk.logdepthbuf_fragment, -"}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;", -THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},equirect:{uniforms:{tEquirect:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", +"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_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,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );", +THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,"\toutgoingLight = diffuseColor.rgb;",THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")}, +lambert:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{emissive:{type:"c",value:new THREE.Color(0)},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#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.logdepthbuf_pars_vertex,"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.logdepthbuf_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.lights_lambert_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_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,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,THREE.ShaderChunk.alphatest_fragment, +THREE.ShaderChunk.specularmap_fragment,"\t#ifdef DOUBLE_SIDED\n\t\tif ( gl_FrontFacing )\n\t\t\toutgoingLight += diffuseColor.rgb * vLightFront + emissive;\n\t\telse\n\t\t\toutgoingLight += diffuseColor.rgb * vLightBack + emissive;\n\t#else\n\t\toutgoingLight += diffuseColor.rgb * vLightFront + emissive;\n\t#endif",THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")}, +phong:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.common,THREE.UniformsLib.bump,THREE.UniformsLib.normalmap,THREE.UniformsLib.fog,THREE.UniformsLib.lights,THREE.UniformsLib.shadowmap,{emissive:{type:"c",value:new THREE.Color(0)},specular:{type:"c",value:new THREE.Color(1118481)},shininess:{type:"f",value:30},wrapRGB:{type:"v3",value:new THREE.Vector3(1,1,1)}}]),vertexShader:["#define PHONG\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif",THREE.ShaderChunk.common, +THREE.ShaderChunk.map_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,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"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,"#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"\tvViewPosition = -mvPosition.xyz;",THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.envmap_vertex,THREE.ShaderChunk.lights_phong_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;", +THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.map_pars_fragment,THREE.ShaderChunk.alphamap_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.logdepthbuf_pars_fragment, +"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphamap_fragment,THREE.ShaderChunk.alphatest_fragment,THREE.ShaderChunk.specularmap_fragment,THREE.ShaderChunk.lights_phong_fragment,THREE.ShaderChunk.lightmap_fragment,THREE.ShaderChunk.envmap_fragment,THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.linear_to_gamma_fragment, +THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")},particle_basic:{uniforms:THREE.UniformsUtils.merge([THREE.UniformsLib.particle,THREE.UniformsLib.shadowmap]),vertexShader:["uniform float size;\nuniform float scale;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.shadowmap_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / length( mvPosition.xyz ) );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\tgl_Position = projectionMatrix * mvPosition;", +THREE.ShaderChunk.logdepthbuf_vertex,THREE.ShaderChunk.worldpos_vertex,THREE.ShaderChunk.shadowmap_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 psColor;\nuniform 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,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( psColor, opacity );", +THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.map_particle_fragment,THREE.ShaderChunk.color_fragment,THREE.ShaderChunk.alphatest_fragment,"\toutgoingLight = diffuseColor.rgb;",THREE.ShaderChunk.shadowmap_fragment,THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].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;\nattribute float lineDistance;\nvarying float vLineDistance;",THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.color_vertex,"\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;",THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;", +THREE.ShaderChunk.common,THREE.ShaderChunk.color_pars_fragment,THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,THREE.ShaderChunk.color_fragment,"\toutgoingLight = diffuseColor.rgb;",THREE.ShaderChunk.fog_fragment,"\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n}"].join("\n")}, +depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3},opacity:{type:"f",value:1}},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float mNear;\nuniform float mFar;\nuniform float opacity;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment, +"void main() {",THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tfloat depth = gl_FragDepthEXT / gl_FragCoord.w;\n\t#else\n\t\tfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n\t#endif\n\tfloat color = 1.0 - smoothstep( mNear, mFar, depth );\n\tgl_FragColor = vec4( vec3( color ), opacity );\n}"].join("\n")},normal:{uniforms:{opacity:{type:"f",value:1}},vertexShader:["varying vec3 vNormal;",THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex, +"void main() {\n\tvNormal = normalize( normalMatrix * normal );",THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform float opacity;\nvarying vec3 vNormal;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\n\tgl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},cube:{uniforms:{tCube:{type:"t",value:null}, +tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform samplerCube tCube;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment, +"void main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );",THREE.ShaderChunk.logdepthbuf_fragment,"}"].join("\n")},equirect:{uniforms:{tEquirect:{type:"t",value:null},tFlip:{type:"f",value:-1}},vertexShader:["varying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {\n\tvWorldPosition = transformDirection( position, modelMatrix );\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:["uniform sampler2D tEquirect;\nuniform float tFlip;\nvarying vec3 vWorldPosition;",THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"void main() {\nvec3 direction = normalize( vWorldPosition );\nvec2 sampleUV;\nsampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );\nsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\ngl_FragColor = texture2D( tEquirect, sampleUV );",THREE.ShaderChunk.logdepthbuf_fragment, "}"].join("\n")},depthRGBA:{uniforms:{},vertexShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.morphtarget_pars_vertex,THREE.ShaderChunk.skinning_pars_vertex,THREE.ShaderChunk.logdepthbuf_pars_vertex,"void main() {",THREE.ShaderChunk.skinbase_vertex,THREE.ShaderChunk.morphtarget_vertex,THREE.ShaderChunk.skinning_vertex,THREE.ShaderChunk.default_vertex,THREE.ShaderChunk.logdepthbuf_vertex,"}"].join("\n"),fragmentShader:[THREE.ShaderChunk.common,THREE.ShaderChunk.logdepthbuf_pars_fragment,"vec4 pack_depth( const in float depth ) {\n\tconst vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );\n\tconst vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );\n\tvec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );\n\tres -= res.xxyz * bit_mask;\n\treturn res;\n}\nvoid main() {", THREE.ShaderChunk.logdepthbuf_fragment,"\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );\n\t#else\n\t\tgl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );\n\t#endif\n}"].join("\n")}}; -THREE.WebGLRenderer=function(a){function b(a){var b=a.geometry;a=a.material;var c=b.vertices.length;if(a.attributes){void 0===b.__webglCustomAttributesList&&(b.__webglCustomAttributesList=[]);for(var d in a.attributes){var e=a.attributes[d];if(!e.__webglInitialized||e.createUniqueBuffers){e.__webglInitialized=!0;var f=1;"v2"===e.type?f=2:"v3"===e.type?f=3:"v4"===e.type?f=4:"c"===e.type&&(f=3);e.size=f;e.array=new Float32Array(c*f);e.buffer=l.createBuffer();e.buffer.belongsToAttribute=d;e.needsUpdate= -!0}b.__webglCustomAttributesList.push(e)}}}function c(a,b){var c=b.geometry,e=a.faces3,f=3*e.length,g=1*e.length,h=3*e.length,e=d(b,a);a.__vertexArray=new Float32Array(3*f);a.__normalArray=new Float32Array(3*f);a.__colorArray=new Float32Array(3*f);a.__uvArray=new Float32Array(2*f);1h&&(e[v].counter+=1,k=e[v].hash+"_"+e[v].counter,k in q||(p={id:nc++,faces3:[],materialIndex:v,vertices:0,numMorphTargets:m,numMorphNormals:n},q[k]=p,r.push(p)));q[k].faces3.push(t);q[k].vertices+=3}f[g]=r;b.groupsNeedUpdate=!1}f=fb[b.id];g=0;for(d=f.length;gY;Y++)qa=P[Y],Pa[Va]=qa.x,Pa[Va+1]=qa.y,Pa[Va+2]=qa.z,Va+=3;else for(Y=0;3>Y;Y++)Pa[Va]=M.x,Pa[Va+1]=M.y,Pa[Va+2]=M.z,Va+=3;l.bindBuffer(l.ARRAY_BUFFER, -v.__webglNormalBuffer);l.bufferData(l.ARRAY_BUFFER,Pa,z)}if(Ma&&Wa){w=0;for(F=V.length;wY;Y++)Da=O[Y],xb[mb]=Da.x,xb[mb+1]=Da.y,mb+=2;0Y;Y++)Aa=U[Y],ob[ya]=Aa.x,ob[ya+1]=Aa.y,ya+=2;0ua;ua++)ib[ua]=!I.autoScaleCubemaps||Gb||ba?ba?ka.image[ua].image:ka.image[ua]:M(ka.image[ua],Gc);var Rb=ib[0],Sb=THREE.Math.isPowerOfTwo(Rb.width)&&THREE.Math.isPowerOfTwo(Rb.height),qb=S(ka.format),Tb=S(ka.type);U(l.TEXTURE_CUBE_MAP,ka,Sb);for(ua=0;6>ua;ua++)if(Gb)for(var zb,Hb=ib[ua].mipmaps,rb=0,Yb=Hb.length;rb=sc&&console.warn("WebGLRenderer: trying to use "+ -a+" texture units while this GPU supports only "+sc);Nb+=1;return a}function G(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getNormalMatrix(a._modelViewMatrix)}function E(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 w(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function D(a){a*=O;a!==tc&&(l.lineWidth(a),tc=a)}function A(a,b,c){uc!==a&&(a?l.enable(l.POLYGON_OFFSET_FILL):l.disable(l.POLYGON_OFFSET_FILL),uc=a);!a||vc===b&&wc===c|| -(l.polygonOffset(b,c),vc=b,wc=c)}function U(a,b,c){c?(l.texParameteri(a,l.TEXTURE_WRAP_S,S(b.wrapS)),l.texParameteri(a,l.TEXTURE_WRAP_T,S(b.wrapT)),l.texParameteri(a,l.TEXTURE_MAG_FILTER,S(b.magFilter)),l.texParameteri(a,l.TEXTURE_MIN_FILTER,S(b.minFilter))):(l.texParameteri(a,l.TEXTURE_WRAP_S,l.CLAMP_TO_EDGE),l.texParameteri(a,l.TEXTURE_WRAP_T,l.CLAMP_TO_EDGE),b.wrapS===THREE.ClampToEdgeWrapping&&b.wrapT===THREE.ClampToEdgeWrapping||console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT is set to THREE.ClampToEdgeWrapping. ( "+ -b.sourceFile+" )"),l.texParameteri(a,l.TEXTURE_MAG_FILTER,N(b.magFilter)),l.texParameteri(a,l.TEXTURE_MIN_FILTER,N(b.minFilter)),b.minFilter!==THREE.NearestFilter&&b.minFilter!==THREE.LinearFilter&&console.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter is set to THREE.LinearFilter or THREE.NearestFilter. ( "+b.sourceFile+" )"));(c=aa.get("EXT_texture_filter_anisotropic"))&&b.type!==THREE.FloatType&&(1b||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElement("canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);console.log("THREE.WebGLRenderer:",a,"is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height+".");return d}return a}function K(a,b){l.bindRenderbuffer(l.RENDERBUFFER, -a);b.depthBuffer&&!b.stencilBuffer?(l.renderbufferStorage(l.RENDERBUFFER,l.DEPTH_COMPONENT16,b.width,b.height),l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_ATTACHMENT,l.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(l.renderbufferStorage(l.RENDERBUFFER,l.DEPTH_STENCIL,b.width,b.height),l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_STENCIL_ATTACHMENT,l.RENDERBUFFER,a)):l.renderbufferStorage(l.RENDERBUFFER,l.RGBA4,b.width,b.height)}function L(a){a instanceof THREE.WebGLRenderTargetCube?(l.bindTexture(l.TEXTURE_CUBE_MAP, -a.__webglTexture),l.generateMipmap(l.TEXTURE_CUBE_MAP),l.bindTexture(l.TEXTURE_CUBE_MAP,null)):(l.bindTexture(l.TEXTURE_2D,a.__webglTexture),l.generateMipmap(l.TEXTURE_2D),l.bindTexture(l.TEXTURE_2D,null))}function N(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?l.NEAREST:l.LINEAR}function S(a){var b;if(a===THREE.RepeatWrapping)return l.REPEAT;if(a===THREE.ClampToEdgeWrapping)return l.CLAMP_TO_EDGE;if(a===THREE.MirroredRepeatWrapping)return l.MIRRORED_REPEAT; -if(a===THREE.NearestFilter)return l.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return l.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return l.NEAREST_MIPMAP_LINEAR;if(a===THREE.LinearFilter)return l.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return l.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return l.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return l.UNSIGNED_BYTE;if(a===THREE.UnsignedShort4444Type)return l.UNSIGNED_SHORT_4_4_4_4;if(a===THREE.UnsignedShort5551Type)return l.UNSIGNED_SHORT_5_5_5_1; -if(a===THREE.UnsignedShort565Type)return l.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return l.BYTE;if(a===THREE.ShortType)return l.SHORT;if(a===THREE.UnsignedShortType)return l.UNSIGNED_SHORT;if(a===THREE.IntType)return l.INT;if(a===THREE.UnsignedIntType)return l.UNSIGNED_INT;if(a===THREE.FloatType)return l.FLOAT;if(a===THREE.AlphaFormat)return l.ALPHA;if(a===THREE.RGBFormat)return l.RGB;if(a===THREE.RGBAFormat)return l.RGBA;if(a===THREE.LuminanceFormat)return l.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return l.LUMINANCE_ALPHA; -if(a===THREE.AddEquation)return l.FUNC_ADD;if(a===THREE.SubtractEquation)return l.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return l.FUNC_REVERSE_SUBTRACT;if(a===THREE.ZeroFactor)return l.ZERO;if(a===THREE.OneFactor)return l.ONE;if(a===THREE.SrcColorFactor)return l.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return l.ONE_MINUS_SRC_COLOR;if(a===THREE.SrcAlphaFactor)return l.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return l.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return l.DST_ALPHA; -if(a===THREE.OneMinusDstAlphaFactor)return l.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return l.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return l.ONE_MINUS_DST_COLOR;if(a===THREE.SrcAlphaSaturateFactor)return l.SRC_ALPHA_SATURATE;b=aa.get("WEBGL_compressed_texture_s3tc");if(null!==b){if(a===THREE.RGB_S3TC_DXT1_Format)return b.COMPRESSED_RGB_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT1_Format)return b.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return b.COMPRESSED_RGBA_S3TC_DXT3_EXT; -if(a===THREE.RGBA_S3TC_DXT5_Format)return b.COMPRESSED_RGBA_S3TC_DXT5_EXT}b=aa.get("WEBGL_compressed_texture_pvrtc");if(null!==b){if(a===THREE.RGB_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(a===THREE.RGB_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(a===THREE.RGBA_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(a===THREE.RGBA_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}b=aa.get("EXT_blend_minmax");if(null!==b){if(a===THREE.MinEquation)return b.MIN_EXT; -if(a===THREE.MaxEquation)return b.MAX_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);a=a||{};var P=void 0!==a.canvas?a.canvas:document.createElement("canvas"),W=void 0!==a.context?a.context:null,O=1,ga=void 0!==a.precision?a.precision:"highp",ea=void 0!==a.alpha?a.alpha:!1,xa=void 0!==a.depth?a.depth:!0,H=void 0!==a.stencil?a.stencil:!0,$a=void 0!==a.antialias?a.antialias:!1,qa=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,ya=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer: -!1,X=void 0!==a.logarithmicDepthBuffer?a.logarithmicDepthBuffer:!1,ta=new THREE.Color(0),Za=0,pa=[],Fa={},Ga=[],Ta=[],za=[],vb=[],gb=[];this.domElement=P;this.context=null;this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.shadowMapEnabled=this.gammaOutput=this.gammaInput=!1;this.shadowMapType=THREE.PCFShadowMap;this.shadowMapCullFace=THREE.CullFaceFront;this.shadowMapCascade=this.shadowMapDebug=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps= -!0;this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var I=this,Xa=[],Xb=null,jb=null,Ib=-1,Sa="",Jb=null,Nb=0,sb=-1,Yb=-1,Zb=-1,dc=-1,ec=-1,fc=-1,gc=-1,hc=-1,ic=-1,jc=-1,kc=-1,uc=null,vc=null,wc=null,tc=null,Ya=0,tb=0,kb=P.width,eb=P.height,xc=0,yc=0,ub=new Uint8Array(16),Ma=new Uint8Array(16),wb=new THREE.Frustum,Cb=new THREE.Matrix4;new THREE.Matrix4;var Da=new THREE.Vector3,ma=new THREE.Vector3,Pb=!0,qc={ambient:[0,0,0],directional:{length:0, -colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[]},hemi:{length:0,skyColors:[],groundColors:[],positions:[]}},l;try{var zc={alpha:ea,depth:xa,stencil:H,antialias:$a,premultipliedAlpha:qa,preserveDrawingBuffer:ya};l=W||P.getContext("webgl",zc)||P.getContext("experimental-webgl",zc);if(null===l){if(null!==P.getContext("webgl"))throw"Error creating WebGL context with your selected attributes."; -throw"Error creating WebGL context.";}P.addEventListener("webglcontextlost",function(a){a.preventDefault();Ac();Bc();Fa={}},!1)}catch(Hc){console.error(Hc)}void 0===l.getShaderPrecisionFormat&&(l.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});var aa=new THREE.WebGLExtensions(l);aa.get("OES_texture_float");aa.get("OES_texture_float_linear");aa.get("OES_standard_derivatives");X&&aa.get("EXT_frag_depth");var Bc=function(){l.clearColor(0,0,0,1);l.clearDepth(1);l.clearStencil(0); -l.enable(l.DEPTH_TEST);l.depthFunc(l.LEQUAL);l.frontFace(l.CCW);l.cullFace(l.BACK);l.enable(l.CULL_FACE);l.enable(l.BLEND);l.blendEquation(l.FUNC_ADD);l.blendFunc(l.SRC_ALPHA,l.ONE_MINUS_SRC_ALPHA);l.viewport(Ya,tb,kb,eb);l.clearColor(ta.r,ta.g,ta.b,Za)},Ac=function(){Jb=Xb=null;Yb=sb=kc=jc=Zb=-1;Sa="";Ib=-1;Pb=!0;for(var a=0;ab;b++)l.deleteFramebuffer(a.__webglFramebuffer[b]),l.deleteRenderbuffer(a.__webglRenderbuffer[b]);else l.deleteFramebuffer(a.__webglFramebuffer),l.deleteRenderbuffer(a.__webglRenderbuffer);delete a.__webglFramebuffer;delete a.__webglRenderbuffer}I.info.memory.textures--},pc=function(a){a=a.target;a.removeEventListener("dispose",pc);oc(a)},Dc=function(a){for(var b= -"__webglVertexBuffer __webglNormalBuffer __webglTangentBuffer __webglColorBuffer __webglUVBuffer __webglUV2Buffer __webglSkinIndicesBuffer __webglSkinWeightsBuffer __webglFaceBuffer __webglLineBuffer __webglLineDistanceBuffer".split(" "),c=0,d=b.length;cd.numSupportedMorphTargets?(n.sort(p),n.length=d.numSupportedMorphTargets):n.length>d.numSupportedMorphNormals?n.sort(p):0===n.length&&n.push([0,0]);for(var m=0,r= -d.numSupportedMorphTargets;mf;f++){a.__webglFramebuffer[f]= -l.createFramebuffer();a.__webglRenderbuffer[f]=l.createRenderbuffer();l.texImage2D(l.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,h=l.TEXTURE_CUBE_MAP_POSITIVE_X+f;l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer[f]);l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,h,g.__webglTexture,0);K(a.__webglRenderbuffer[f],a)}c&&l.generateMipmap(l.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=l.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer: -l.createRenderbuffer(),l.bindTexture(l.TEXTURE_2D,a.__webglTexture),U(l.TEXTURE_2D,a,c),l.texImage2D(l.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=l.TEXTURE_2D,l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer),l.framebufferTexture2D(l.FRAMEBUFFER,l.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?l.framebufferRenderbuffer(l.FRAMEBUFFER,l.DEPTH_ATTACHMENT,l.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&l.framebufferRenderbuffer(l.FRAMEBUFFER, -l.DEPTH_STENCIL_ATTACHMENT,l.RENDERBUFFER,a.__webglRenderbuffer):K(a.__webglRenderbuffer,a),c&&l.generateMipmap(l.TEXTURE_2D);b?l.bindTexture(l.TEXTURE_CUBE_MAP,null):l.bindTexture(l.TEXTURE_2D,null);l.bindRenderbuffer(l.RENDERBUFFER,null);l.bindFramebuffer(l.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=kb,a=eb,d=Ya,e=tb);b!==jb&&(l.bindFramebuffer(l.FRAMEBUFFER,b),l.viewport(d,e,c,a),jb=b);xc=c;yc=a};this.readRenderTargetPixels= -function(a,b,c,d,e,f){if(!(a instanceof THREE.WebGLRenderTarget))console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");else if(a.__webglFramebuffer)if(a.format!==THREE.RGBAFormat)console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.");else{var g=!1;a.__webglFramebuffer!==jb&&(l.bindFramebuffer(l.FRAMEBUFFER,a.__webglFramebuffer),g=!0);l.checkFramebufferStatus(l.FRAMEBUFFER)=== -l.FRAMEBUFFER_COMPLETE?l.readPixels(b,c,d,e,l.RGBA,l.UNSIGNED_BYTE,f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.");g&&l.bindFramebuffer(l.FRAMEBUFFER,jb)}};this.initMaterial=function(){console.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")};this.addPrePlugin=function(){console.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")};this.addPostPlugin=function(){console.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")}; -this.updateShadowMap=function(){console.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")}}; +THREE.WebGLRenderer=function(a){function b(a){var b=a.geometry;a=a.material;var c=b.vertices.length;if(a.attributes){void 0===b.__webglCustomAttributesList&&(b.__webglCustomAttributesList=[]);for(var d in a.attributes){var e=a.attributes[d];if(!e.__webglInitialized||e.createUniqueBuffers){e.__webglInitialized=!0;var f=1;"v2"===e.type?f=2:"v3"===e.type?f=3:"v4"===e.type?f=4:"c"===e.type&&(f=3);e.size=f;e.array=new Float32Array(c*f);e.buffer=m.createBuffer();e.buffer.belongsToAttribute=d;e.needsUpdate= +!0}b.__webglCustomAttributesList.push(e)}}}function c(a,b){return a.material instanceof THREE.MeshFaceMaterial?a.material.materials[b.materialIndex]:a.material}function d(a,b,c,d){c=c.attributes;var e=b.attributes;b=b.attributesKeys;for(var f=0,g=b.length;fh&&(e[u].counter+=1,k=e[u].hash+"_"+e[u].counter,k in s||(q={id:Qb++,faces3:[],materialIndex:u,vertices:0,numMorphTargets:l, +numMorphNormals:p},s[k]=q,t.push(q)));s[k].faces3.push(r);s[k].vertices+=3}f[g]=t;b.groupsNeedUpdate=!1}f=Ua[b.id];g=0;for(d=f.length;gY;Y++)pa=I[Y],Na[Ra]=pa.x,Na[Ra+1]= +pa.y,Na[Ra+2]=pa.z,Ra+=3;else for(Y=0;3>Y;Y++)Na[Ra]=H.x,Na[Ra+1]=H.y,Na[Ra+2]=H.z,Ra+=3;m.bindBuffer(m.ARRAY_BUFFER,v.__webglNormalBuffer);m.bufferData(m.ARRAY_BUFFER,Na,D)}if(vb&&Hb){y=0;for(z=$.length;yY;Y++)ab=U[Y],Ab[kb]=ab.x,Ab[kb+1]=ab.y,kb+=2;0Y;Y++)oa=O[Y],lb[yb]=oa.x,lb[yb+1]=oa.y, +yb+=2;0ya;ya++)gb[ya]=!B.autoScaleCubemaps||Rb||Ib?Ib? +X.image[ya].image:X.image[ya]:E(X.image[ya],qc);var Yb=gb[0],Zb=THREE.Math.isPowerOfTwo(Yb.width)&&THREE.Math.isPowerOfTwo(Yb.height),Wa=I(X.format),tb=I(X.type);A(m.TEXTURE_CUBE_MAP,X,Zb);for(ya=0;6>ya;ya++)if(Rb)for(var hb,$b=gb[ya].mipmaps,Fb=0,Sb=$b.length;Fb=Wb&&THREE.warn("WebGLRenderer: trying to use "+a+" texture units while this GPU supports only "+Wb);Mb+=1;return a}function w(a,b){a._modelViewMatrix.multiplyMatrices(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getNormalMatrix(a._modelViewMatrix)} +function y(a,b,c,d){a[b]=c.r*d;a[b+1]=c.g*d;a[b+2]=c.b*d}function A(a,b,c){c?(m.texParameteri(a,m.TEXTURE_WRAP_S,I(b.wrapS)),m.texParameteri(a,m.TEXTURE_WRAP_T,I(b.wrapT)),m.texParameteri(a,m.TEXTURE_MAG_FILTER,I(b.magFilter)),m.texParameteri(a,m.TEXTURE_MIN_FILTER,I(b.minFilter))):(m.texParameteri(a,m.TEXTURE_WRAP_S,m.CLAMP_TO_EDGE),m.texParameteri(a,m.TEXTURE_WRAP_T,m.CLAMP_TO_EDGE),b.wrapS===THREE.ClampToEdgeWrapping&&b.wrapT===THREE.ClampToEdgeWrapping||THREE.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( "+ +b.sourceFile+" )"),m.texParameteri(a,m.TEXTURE_MAG_FILTER,z(b.magFilter)),m.texParameteri(a,m.TEXTURE_MIN_FILTER,z(b.minFilter)),b.minFilter!==THREE.NearestFilter&&b.minFilter!==THREE.LinearFilter&&THREE.warn("THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( "+b.sourceFile+" )"));(c=da.get("EXT_texture_filter_anisotropic"))&&b.type!==THREE.FloatType&&b.type!==THREE.HalfFloatType&&(1b||a.height>b){var c=b/Math.max(a.width,a.height),d=document.createElement("canvas");d.width=Math.floor(a.width*c);d.height=Math.floor(a.height*c);d.getContext("2d").drawImage(a,0,0,a.width,a.height,0,0,d.width,d.height);THREE.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+d.width+"x"+d.height,a);return d}return a} +function G(a,b){m.bindRenderbuffer(m.RENDERBUFFER,a);b.depthBuffer&&!b.stencilBuffer?(m.renderbufferStorage(m.RENDERBUFFER,m.DEPTH_COMPONENT16,b.width,b.height),m.framebufferRenderbuffer(m.FRAMEBUFFER,m.DEPTH_ATTACHMENT,m.RENDERBUFFER,a)):b.depthBuffer&&b.stencilBuffer?(m.renderbufferStorage(m.RENDERBUFFER,m.DEPTH_STENCIL,b.width,b.height),m.framebufferRenderbuffer(m.FRAMEBUFFER,m.DEPTH_STENCIL_ATTACHMENT,m.RENDERBUFFER,a)):m.renderbufferStorage(m.RENDERBUFFER,m.RGBA4,b.width,b.height)}function F(a){a instanceof +THREE.WebGLRenderTargetCube?(m.bindTexture(m.TEXTURE_CUBE_MAP,a.__webglTexture),m.generateMipmap(m.TEXTURE_CUBE_MAP),m.bindTexture(m.TEXTURE_CUBE_MAP,null)):(m.bindTexture(m.TEXTURE_2D,a.__webglTexture),m.generateMipmap(m.TEXTURE_2D),m.bindTexture(m.TEXTURE_2D,null))}function z(a){return a===THREE.NearestFilter||a===THREE.NearestMipMapNearestFilter||a===THREE.NearestMipMapLinearFilter?m.NEAREST:m.LINEAR}function I(a){var b;if(a===THREE.RepeatWrapping)return m.REPEAT;if(a===THREE.ClampToEdgeWrapping)return m.CLAMP_TO_EDGE; +if(a===THREE.MirroredRepeatWrapping)return m.MIRRORED_REPEAT;if(a===THREE.NearestFilter)return m.NEAREST;if(a===THREE.NearestMipMapNearestFilter)return m.NEAREST_MIPMAP_NEAREST;if(a===THREE.NearestMipMapLinearFilter)return m.NEAREST_MIPMAP_LINEAR;if(a===THREE.LinearFilter)return m.LINEAR;if(a===THREE.LinearMipMapNearestFilter)return m.LINEAR_MIPMAP_NEAREST;if(a===THREE.LinearMipMapLinearFilter)return m.LINEAR_MIPMAP_LINEAR;if(a===THREE.UnsignedByteType)return m.UNSIGNED_BYTE;if(a===THREE.UnsignedShort4444Type)return m.UNSIGNED_SHORT_4_4_4_4; +if(a===THREE.UnsignedShort5551Type)return m.UNSIGNED_SHORT_5_5_5_1;if(a===THREE.UnsignedShort565Type)return m.UNSIGNED_SHORT_5_6_5;if(a===THREE.ByteType)return m.BYTE;if(a===THREE.ShortType)return m.SHORT;if(a===THREE.UnsignedShortType)return m.UNSIGNED_SHORT;if(a===THREE.IntType)return m.INT;if(a===THREE.UnsignedIntType)return m.UNSIGNED_INT;if(a===THREE.FloatType)return m.FLOAT;b=da.get("OES_texture_half_float");if(null!==b&&a===THREE.HalfFloatType)return b.HALF_FLOAT_OES;if(a===THREE.AlphaFormat)return m.ALPHA; +if(a===THREE.RGBFormat)return m.RGB;if(a===THREE.RGBAFormat)return m.RGBA;if(a===THREE.LuminanceFormat)return m.LUMINANCE;if(a===THREE.LuminanceAlphaFormat)return m.LUMINANCE_ALPHA;if(a===THREE.AddEquation)return m.FUNC_ADD;if(a===THREE.SubtractEquation)return m.FUNC_SUBTRACT;if(a===THREE.ReverseSubtractEquation)return m.FUNC_REVERSE_SUBTRACT;if(a===THREE.ZeroFactor)return m.ZERO;if(a===THREE.OneFactor)return m.ONE;if(a===THREE.SrcColorFactor)return m.SRC_COLOR;if(a===THREE.OneMinusSrcColorFactor)return m.ONE_MINUS_SRC_COLOR; +if(a===THREE.SrcAlphaFactor)return m.SRC_ALPHA;if(a===THREE.OneMinusSrcAlphaFactor)return m.ONE_MINUS_SRC_ALPHA;if(a===THREE.DstAlphaFactor)return m.DST_ALPHA;if(a===THREE.OneMinusDstAlphaFactor)return m.ONE_MINUS_DST_ALPHA;if(a===THREE.DstColorFactor)return m.DST_COLOR;if(a===THREE.OneMinusDstColorFactor)return m.ONE_MINUS_DST_COLOR;if(a===THREE.SrcAlphaSaturateFactor)return m.SRC_ALPHA_SATURATE;b=da.get("WEBGL_compressed_texture_s3tc");if(null!==b){if(a===THREE.RGB_S3TC_DXT1_Format)return b.COMPRESSED_RGB_S3TC_DXT1_EXT; +if(a===THREE.RGBA_S3TC_DXT1_Format)return b.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(a===THREE.RGBA_S3TC_DXT3_Format)return b.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(a===THREE.RGBA_S3TC_DXT5_Format)return b.COMPRESSED_RGBA_S3TC_DXT5_EXT}b=da.get("WEBGL_compressed_texture_pvrtc");if(null!==b){if(a===THREE.RGB_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(a===THREE.RGB_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(a===THREE.RGBA_PVRTC_4BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; +if(a===THREE.RGBA_PVRTC_2BPPV1_Format)return b.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}b=da.get("EXT_blend_minmax");if(null!==b){if(a===THREE.MinEquation)return b.MIN_EXT;if(a===THREE.MaxEquation)return b.MAX_EXT}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);a=a||{};var U=void 0!==a.canvas?a.canvas:document.createElement("canvas"),M=void 0!==a.context?a.context:null,H=1,L=void 0!==a.precision?a.precision:"highp",P=void 0!==a.alpha?a.alpha:!1,N=void 0!==a.depth?a.depth:!0,R=void 0!==a.stencil? +a.stencil:!0,V=void 0!==a.antialias?a.antialias:!1,J=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,oa=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,ja=void 0!==a.logarithmicDepthBuffer?a.logarithmicDepthBuffer:!1,ha=new THREE.Color(0),O=0,ca=[],ba={},qa=[],Ka=[],Qa=[],Xa=[],Ya=[];this.domElement=U;this.context=null;this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=!0;this.gammaFactor=2;this.shadowMapEnabled=this.gammaOutput=this.gammaInput= +!1;this.shadowMapType=THREE.PCFShadowMap;this.shadowMapCullFace=THREE.CullFaceFront;this.shadowMapCascade=this.shadowMapDebug=!1;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=!0;this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var B=this,Pa=[],ob=null,ab=null,ub=-1,ta="",vb=null,Mb=0,ib=0,bb=0,pb=U.width,qb=U.height,Xb=0,fc=0,cb=new THREE.Frustum,db=new THREE.Matrix4,wa=new THREE.Vector3,pa=new THREE.Vector3,Ob=!0,jc={ambient:[0, +0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[],decays:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],anglesCos:[],exponents:[],decays:[]},hemi:{length:0,skyColors:[],groundColors:[],positions:[]}},m;try{var Yb={alpha:P,depth:N,stencil:R,antialias:V,premultipliedAlpha:J,preserveDrawingBuffer:oa};m=M||U.getContext("webgl",Yb)||U.getContext("experimental-webgl",Yb);if(null===m){if(null!==U.getContext("webgl"))throw"Error creating WebGL context with your selected attributes."; +throw"Error creating WebGL context.";}U.addEventListener("webglcontextlost",function(a){a.preventDefault();Zb();lc();ba={}},!1)}catch(rc){THREE.error("THREE.WebGLRenderer: "+rc)}var W=new THREE.WebGLState(m,I);void 0===m.getShaderPrecisionFormat&&(m.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}});var da=new THREE.WebGLExtensions(m);da.get("OES_texture_float");da.get("OES_texture_float_linear");da.get("OES_texture_half_float");da.get("OES_texture_half_float_linear"); +da.get("OES_standard_derivatives");ja&&da.get("EXT_frag_depth");var rb=function(a,b,c,d){!0===J&&(a*=d,b*=d,c*=d);m.clearColor(a,b,c,d)},lc=function(){m.clearColor(0,0,0,1);m.clearDepth(1);m.clearStencil(0);m.enable(m.DEPTH_TEST);m.depthFunc(m.LEQUAL);m.frontFace(m.CCW);m.cullFace(m.BACK);m.enable(m.CULL_FACE);m.enable(m.BLEND);m.blendEquation(m.FUNC_ADD);m.blendFunc(m.SRC_ALPHA,m.ONE_MINUS_SRC_ALPHA);m.viewport(ib,bb,pb,qb);rb(ha.r,ha.g,ha.b,O)},Zb=function(){vb=ob=null;ta="";ub=-1;Ob=!0;W.reset()}; +lc();this.context=m;this.state=W;var Wb=m.getParameter(m.MAX_TEXTURE_IMAGE_UNITS),sc=m.getParameter(m.MAX_VERTEX_TEXTURE_IMAGE_UNITS),tc=m.getParameter(m.MAX_TEXTURE_SIZE),qc=m.getParameter(m.MAX_CUBE_MAP_TEXTURE_SIZE),Vb=0b;b++)m.deleteFramebuffer(a.__webglFramebuffer[b]),m.deleteRenderbuffer(a.__webglRenderbuffer[b]);else m.deleteFramebuffer(a.__webglFramebuffer),m.deleteRenderbuffer(a.__webglRenderbuffer);delete a.__webglFramebuffer;delete a.__webglRenderbuffer}B.info.memory.textures--},ic=function(a){a=a.target;a.removeEventListener("dispose",ic);hc(a)},nc=function(a){for(var b= +"__webglVertexBuffer __webglNormalBuffer __webglTangentBuffer __webglColorBuffer __webglUVBuffer __webglUV2Buffer __webglSkinIndicesBuffer __webglSkinWeightsBuffer __webglFaceBuffer __webglLineBuffer __webglLineDistanceBuffer".split(" "),c=0,d=b.length;ch.length&&(console.warn("THREE.WebGLRenderer: Influences array is bigger than morphTargets array."),n.length=h.length);h=0;for(l=n.length;hd.numSupportedMorphTargets?(k.sort(g),k.length=d.numSupportedMorphTargets):k.length>d.numSupportedMorphNormals?k.sort(g):0===k.length&&k.push([0,0]);for(var h=0,p=d.numSupportedMorphTargets;hf;f++){a.__webglFramebuffer[f]=m.createFramebuffer();a.__webglRenderbuffer[f]=m.createRenderbuffer();m.texImage2D(m.TEXTURE_CUBE_MAP_POSITIVE_X+f,0,d,a.width,a.height,0,d,e,null);var g=a,h=m.TEXTURE_CUBE_MAP_POSITIVE_X+f;m.bindFramebuffer(m.FRAMEBUFFER, +a.__webglFramebuffer[f]);m.framebufferTexture2D(m.FRAMEBUFFER,m.COLOR_ATTACHMENT0,h,g.__webglTexture,0);G(a.__webglRenderbuffer[f],a)}c&&m.generateMipmap(m.TEXTURE_CUBE_MAP)}else a.__webglFramebuffer=m.createFramebuffer(),a.__webglRenderbuffer=a.shareDepthFrom?a.shareDepthFrom.__webglRenderbuffer:m.createRenderbuffer(),m.bindTexture(m.TEXTURE_2D,a.__webglTexture),A(m.TEXTURE_2D,a,c),m.texImage2D(m.TEXTURE_2D,0,d,a.width,a.height,0,d,e,null),d=m.TEXTURE_2D,m.bindFramebuffer(m.FRAMEBUFFER,a.__webglFramebuffer), +m.framebufferTexture2D(m.FRAMEBUFFER,m.COLOR_ATTACHMENT0,d,a.__webglTexture,0),a.shareDepthFrom?a.depthBuffer&&!a.stencilBuffer?m.framebufferRenderbuffer(m.FRAMEBUFFER,m.DEPTH_ATTACHMENT,m.RENDERBUFFER,a.__webglRenderbuffer):a.depthBuffer&&a.stencilBuffer&&m.framebufferRenderbuffer(m.FRAMEBUFFER,m.DEPTH_STENCIL_ATTACHMENT,m.RENDERBUFFER,a.__webglRenderbuffer):G(a.__webglRenderbuffer,a),c&&m.generateMipmap(m.TEXTURE_2D);b?m.bindTexture(m.TEXTURE_CUBE_MAP,null):m.bindTexture(m.TEXTURE_2D,null);m.bindRenderbuffer(m.RENDERBUFFER, +null);m.bindFramebuffer(m.FRAMEBUFFER,null)}a?(b=b?a.__webglFramebuffer[a.activeCubeFace]:a.__webglFramebuffer,c=a.width,a=a.height,e=d=0):(b=null,c=pb,a=qb,d=ib,e=bb);b!==ab&&(m.bindFramebuffer(m.FRAMEBUFFER,b),m.viewport(d,e,c,a),ab=b);Xb=c;fc=a};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(!(a instanceof THREE.WebGLRenderTarget))console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");else if(a.__webglFramebuffer)if(a.format!==THREE.RGBAFormat)console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format."); +else{var g=!1;a.__webglFramebuffer!==ab&&(m.bindFramebuffer(m.FRAMEBUFFER,a.__webglFramebuffer),g=!0);m.checkFramebufferStatus(m.FRAMEBUFFER)===m.FRAMEBUFFER_COMPLETE?m.readPixels(b,c,d,e,m.RGBA,m.UNSIGNED_BYTE,f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.");g&&m.bindFramebuffer(m.FRAMEBUFFER,ab)}};this.initMaterial=function(){THREE.warn("THREE.WebGLRenderer: .initMaterial() has been removed.")};this.addPrePlugin=function(){THREE.warn("THREE.WebGLRenderer: .addPrePlugin() has been removed.")}; +this.addPostPlugin=function(){THREE.warn("THREE.WebGLRenderer: .addPostPlugin() has been removed.")};this.updateShadowMap=function(){THREE.warn("THREE.WebGLRenderer: .updateShadowMap() has been removed.")}}; THREE.WebGLRenderTarget=function(a,b,c){this.width=a;this.height=b;c=c||{};this.wrapS=void 0!==c.wrapS?c.wrapS:THREE.ClampToEdgeWrapping;this.wrapT=void 0!==c.wrapT?c.wrapT:THREE.ClampToEdgeWrapping;this.magFilter=void 0!==c.magFilter?c.magFilter:THREE.LinearFilter;this.minFilter=void 0!==c.minFilter?c.minFilter:THREE.LinearMipMapLinearFilter;this.anisotropy=void 0!==c.anisotropy?c.anisotropy:1;this.offset=new THREE.Vector2(0,0);this.repeat=new THREE.Vector2(1,1);this.format=void 0!==c.format?c.format: THREE.RGBAFormat;this.type=void 0!==c.type?c.type:THREE.UnsignedByteType;this.depthBuffer=void 0!==c.depthBuffer?c.depthBuffer:!0;this.stencilBuffer=void 0!==c.stencilBuffer?c.stencilBuffer:!0;this.generateMipmaps=!0;this.shareDepthFrom=void 0!==c.shareDepthFrom?c.shareDepthFrom:null}; THREE.WebGLRenderTarget.prototype={constructor:THREE.WebGLRenderTarget,setSize:function(a,b){this.width=a;this.height=b},clone:function(){var a=new THREE.WebGLRenderTarget(this.width,this.height);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;return a},dispose:function(){this.dispatchEvent({type:"dispose"})}};THREE.EventDispatcher.prototype.apply(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube=function(a,b,c){THREE.WebGLRenderTarget.call(this,a,b,c);this.activeCubeFace=0};THREE.WebGLRenderTargetCube.prototype=Object.create(THREE.WebGLRenderTarget.prototype);THREE.WebGLRenderTargetCube.prototype.constructor=THREE.WebGLRenderTargetCube; THREE.WebGLExtensions=function(a){var b={};this.get=function(c){if(void 0!==b[c])return b[c];var d;switch(c){case "EXT_texture_filter_anisotropic":d=a.getExtension("EXT_texture_filter_anisotropic")||a.getExtension("MOZ_EXT_texture_filter_anisotropic")||a.getExtension("WEBKIT_EXT_texture_filter_anisotropic");break;case "WEBGL_compressed_texture_s3tc":d=a.getExtension("WEBGL_compressed_texture_s3tc")||a.getExtension("MOZ_WEBGL_compressed_texture_s3tc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"); -break;case "WEBGL_compressed_texture_pvrtc":d=a.getExtension("WEBGL_compressed_texture_pvrtc")||a.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc");break;default:d=a.getExtension(c)}null===d&&console.log("THREE.WebGLRenderer: "+c+" extension not supported.");return b[c]=d}}; -THREE.WebGLProgram=function(){var a=0;return function(b,c,d,e){var f=b.context,g=d.defines,h=d.__webglShader.uniforms,k=d.attributes,n=d.__webglShader.vertexShader,p=d.__webglShader.fragmentShader,q=d.index0AttributeName;void 0===q&&!0===e.morphTargets&&(q="position");var m="SHADOWMAP_TYPE_BASIC";e.shadowMapType===THREE.PCFShadowMap?m="SHADOWMAP_TYPE_PCF":e.shadowMapType===THREE.PCFSoftShadowMap&&(m="SHADOWMAP_TYPE_PCF_SOFT");var t="ENVMAP_TYPE_CUBE",s="ENVMAP_MODE_REFLECTION",r="ENVMAP_BLENDING_MULTIPLY"; -if(e.envMap){switch(d.envMap.mapping){case THREE.CubeReflectionMapping:case THREE.CubeRefractionMapping:t="ENVMAP_TYPE_CUBE";break;case THREE.EquirectangularReflectionMapping:case THREE.EquirectangularRefractionMapping:t="ENVMAP_TYPE_EQUIREC";break;case THREE.SphericalReflectionMapping:t="ENVMAP_TYPE_SPHERE"}switch(d.envMap.mapping){case THREE.CubeRefractionMapping:case THREE.EquirectangularRefractionMapping:s="ENVMAP_MODE_REFRACTION"}switch(d.combine){case THREE.MultiplyOperation:r="ENVMAP_BLENDING_MULTIPLY"; -break;case THREE.MixOperation:r="ENVMAP_BLENDING_MIX";break;case THREE.AddOperation:r="ENVMAP_BLENDING_ADD"}}var u,v;u=[];for(var y in g)v=g[y],!1!==v&&(v="#define "+y+" "+v,u.push(v));u=u.join("\n");g=f.createProgram();d instanceof THREE.RawShaderMaterial?b=d="":(d=["precision "+e.precision+" float;","precision "+e.precision+" int;",u,e.supportsVertexTextures?"#define VERTEX_TEXTURES":"",b.gammaInput?"#define GAMMA_INPUT":"",b.gammaOutput?"#define GAMMA_OUTPUT":"","#define MAX_DIR_LIGHTS "+e.maxDirLights, -"#define MAX_POINT_LIGHTS "+e.maxPointLights,"#define MAX_SPOT_LIGHTS "+e.maxSpotLights,"#define MAX_HEMI_LIGHTS "+e.maxHemiLights,"#define MAX_SHADOWS "+e.maxShadows,"#define MAX_BONES "+e.maxBones,e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.envMap?"#define "+s:"",e.lightMap?"#define USE_LIGHTMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.vertexColors?"#define USE_COLOR": -"",e.skinning?"#define USE_SKINNING":"",e.useVertexTexture?"#define BONE_TEXTURE":"",e.morphTargets?"#define USE_MORPHTARGETS":"",e.morphNormals?"#define USE_MORPHNORMALS":"",e.wrapAround?"#define WRAP_AROUND":"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+m:"",e.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",e.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",e.sizeAttenuation?"#define USE_SIZEATTENUATION": -"",e.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 modelMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\n\tattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\n\tattribute vec3 morphTarget0;\n\tattribute vec3 morphTarget1;\n\tattribute vec3 morphTarget2;\n\tattribute vec3 morphTarget3;\n\t#ifdef USE_MORPHNORMALS\n\t\tattribute vec3 morphNormal0;\n\t\tattribute vec3 morphNormal1;\n\t\tattribute vec3 morphNormal2;\n\t\tattribute vec3 morphNormal3;\n\t#else\n\t\tattribute vec3 morphTarget4;\n\t\tattribute vec3 morphTarget5;\n\t\tattribute vec3 morphTarget6;\n\t\tattribute vec3 morphTarget7;\n\t#endif\n#endif\n#ifdef USE_SKINNING\n\tattribute vec4 skinIndex;\n\tattribute vec4 skinWeight;\n#endif\n"].join("\n"), -b=["precision "+e.precision+" float;","precision "+e.precision+" int;",e.bumpMap||e.normalMap?"#extension GL_OES_standard_derivatives : enable":"",u,"#define MAX_DIR_LIGHTS "+e.maxDirLights,"#define MAX_POINT_LIGHTS "+e.maxPointLights,"#define MAX_SPOT_LIGHTS "+e.maxSpotLights,"#define MAX_HEMI_LIGHTS "+e.maxHemiLights,"#define MAX_SHADOWS "+e.maxShadows,e.alphaTest?"#define ALPHATEST "+e.alphaTest:"",b.gammaInput?"#define GAMMA_INPUT":"",b.gammaOutput?"#define GAMMA_OUTPUT":"",e.useFog&&e.fog?"#define USE_FOG": -"",e.useFog&&e.fogExp?"#define FOG_EXP2":"",e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.envMap?"#define "+t:"",e.envMap?"#define "+s:"",e.envMap?"#define "+r:"",e.lightMap?"#define USE_LIGHTMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.vertexColors?"#define USE_COLOR":"",e.metal?"#define METAL":"",e.wrapAround?"#define WRAP_AROUND":"",e.doubleSided?"#define DOUBLE_SIDED": -"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+m:"",e.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",e.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",e.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n"));n=new THREE.WebGLShader(f,f.VERTEX_SHADER,d+n);p=new THREE.WebGLShader(f,f.FRAGMENT_SHADER,b+p);f.attachShader(g,n);f.attachShader(g,p);void 0!==q&&f.bindAttribLocation(g, -0,q);f.linkProgram(g);!1===f.getProgramParameter(g,f.LINK_STATUS)&&(console.error("THREE.WebGLProgram: Could not initialise shader."),console.error("gl.VALIDATE_STATUS",f.getProgramParameter(g,f.VALIDATE_STATUS)),console.error("gl.getError()",f.getError()));""!==f.getProgramInfoLog(g)&&console.warn("THREE.WebGLProgram: gl.getProgramInfoLog()",f.getProgramInfoLog(g));f.deleteShader(n);f.deleteShader(p);q="viewMatrix modelViewMatrix projectionMatrix normalMatrix modelMatrix cameraPosition morphTargetInfluences bindMatrix bindMatrixInverse".split(" "); -e.useVertexTexture?(q.push("boneTexture"),q.push("boneTextureWidth"),q.push("boneTextureHeight")):q.push("boneGlobalMatrices");e.logarithmicDepthBuffer&&q.push("logDepthBufFC");for(var C in h)q.push(C);h=q;C={};q=0;for(b=h.length;qL;L++)A[L]=new THREE.Vector3,w[L]=new THREE.Vector3;A=D.shadowCascadeNearZ[K];D=D.shadowCascadeFarZ[K];w[0].set(-1,-1,A);w[1].set(1,-1,A);w[2].set(-1,1,A);w[3].set(1,1,A);w[4].set(-1,-1,D);w[5].set(1,-1,D);w[6].set(-1,1,D);w[7].set(1,1,D);M.originalCamera=v;w=new THREE.Gyroscope;w.position.copy(z.shadowCascadeOffset);w.add(M);w.add(M.target);v.add(w);z.shadowCascadeArray[E]=M;console.log("Created virtualLight",M)}K= -z;A=E;D=K.shadowCascadeArray[A];D.position.copy(K.position);D.target.position.copy(K.target.position);D.lookAt(D.target);D.shadowCameraVisible=K.shadowCameraVisible;D.shadowDarkness=K.shadowDarkness;D.shadowBias=K.shadowCascadeBias[A];w=K.shadowCascadeNearZ[A];K=K.shadowCascadeFarZ[A];D=D.pointsFrustum;D[0].z=w;D[1].z=w;D[2].z=w;D[3].z=w;D[4].z=K;D[5].z=K;D[6].z=K;D[7].z=K;U[G]=M;G++}else U[G]=z,G++;u=0;for(F=U.length;uK;K++)A=D[K],A.copy(w[K]),A.unproject(E),A.applyMatrix4(G.matrixWorldInverse),A.xt.x&&(t.x=A.x),A.yt.y&&(t.y=A.y),A.zt.z&&(t.z=A.z);G.left=m.x;G.right=t.x;G.top=t.y;G.bottom=m.y;G.updateProjectionMatrix()}G=z.shadowMap;w=z.shadowMatrix;E=z.shadowCamera;E.position.setFromMatrixPosition(z.matrixWorld);s.setFromMatrixPosition(z.target.matrixWorld);E.lookAt(s);E.updateMatrixWorld();E.matrixWorldInverse.getInverse(E.matrixWorld);z.cameraHelper&& -(z.cameraHelper.visible=z.shadowCameraVisible);z.shadowCameraVisible&&z.cameraHelper.update();w.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1);w.multiply(E.projectionMatrix);w.multiply(E.matrixWorldInverse);q.multiplyMatrices(E.projectionMatrix,E.matrixWorldInverse);p.setFromMatrix(q);a.setRenderTarget(G);a.clear();r.length=0;e(c,c,E);z=0;for(G=r.length;z 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"].join("\n")); -x.compileShader(L);x.compileShader(N);x.attachShader(K,L);x.attachShader(K,N);x.linkProgram(K);G=K;v=x.getAttribLocation(G,"position");y=x.getAttribLocation(G,"uv");c=x.getUniformLocation(G,"uvOffset");d=x.getUniformLocation(G,"uvScale");e=x.getUniformLocation(G,"rotation");f=x.getUniformLocation(G,"scale");g=x.getUniformLocation(G,"color");h=x.getUniformLocation(G,"map");k=x.getUniformLocation(G,"opacity");n=x.getUniformLocation(G,"modelViewMatrix");p=x.getUniformLocation(G,"projectionMatrix");q= -x.getUniformLocation(G,"fogType");m=x.getUniformLocation(G,"fogDensity");t=x.getUniformLocation(G,"fogNear");s=x.getUniformLocation(G,"fogFar");r=x.getUniformLocation(G,"fogColor");u=x.getUniformLocation(G,"alphaTest");K=document.createElement("canvas");K.width=8;K.height=8;L=K.getContext("2d");L.fillStyle="white";L.fillRect(0,0,8,8);E=new THREE.Texture(K);E.needsUpdate=!0}x.useProgram(G);x.enableVertexAttribArray(v);x.enableVertexAttribArray(y);x.disable(x.CULL_FACE);x.enable(x.BLEND);x.bindBuffer(x.ARRAY_BUFFER, -F);x.vertexAttribPointer(v,2,x.FLOAT,!1,16,0);x.vertexAttribPointer(y,2,x.FLOAT,!1,16,8);x.bindBuffer(x.ELEMENT_ARRAY_BUFFER,z);x.uniformMatrix4fv(p,!1,M.projectionMatrix.elements);x.activeTexture(x.TEXTURE0);x.uniform1i(h,0);L=K=0;(N=U.fog)?(x.uniform3f(r,N.color.r,N.color.g,N.color.b),N instanceof THREE.Fog?(x.uniform1f(t,N.near),x.uniform1f(s,N.far),x.uniform1i(q,1),L=K=1):N instanceof THREE.FogExp2&&(x.uniform1f(m,N.density),x.uniform1i(q,2),L=K=2)):(x.uniform1i(q,0),L=K=0);for(var N=0,S=b.length;N< -S;N++){var P=b[N];P._modelViewMatrix.multiplyMatrices(M.matrixWorldInverse,P.matrixWorld);P.z=-P._modelViewMatrix.elements[14]}b.sort(C);for(var W=[],N=0,S=b.length;NL;L++)I[L]=new THREE.Vector3,F[L]=new THREE.Vector3;I=z.shadowCascadeNearZ[H];z=z.shadowCascadeFarZ[H];F[0].set(-1,-1,I);F[1].set(1,-1,I);F[2].set(-1,1,I);F[3].set(1,1,I);F[4].set(-1,-1,z);F[5].set(1,-1,z);F[6].set(-1,1,z);F[7].set(1,1,z);M.originalCamera=v;F=new THREE.Gyroscope;F.position.copy(A.shadowCascadeOffset);F.add(M);F.add(M.target);v.add(F);A.shadowCascadeArray[G]=M}H=A;I=G;z=H.shadowCascadeArray[I];z.position.copy(H.position); +z.target.position.copy(H.target.position);z.lookAt(z.target);z.shadowCameraVisible=H.shadowCameraVisible;z.shadowDarkness=H.shadowDarkness;z.shadowBias=H.shadowCascadeBias[I];F=H.shadowCascadeNearZ[I];H=H.shadowCascadeFarZ[I];z=z.pointsFrustum;z[0].z=F;z[1].z=F;z[2].z=F;z[3].z=F;z[4].z=H;z[5].z=H;z[6].z=H;z[7].z=H;U[E]=M;E++}else U[E]=A,E++;u=0;for(y=U.length;u +H;H++)I=z[H],I.copy(F[H]),I.unproject(G),I.applyMatrix4(E.matrixWorldInverse),I.xt.x&&(t.x=I.x),I.yt.y&&(t.y=I.y),I.zt.z&&(t.z=I.z);E.left=n.x;E.right=t.x;E.top=t.y;E.bottom=n.y;E.updateProjectionMatrix()}E=A.shadowMap;F=A.shadowMatrix;G=A.shadowCamera;G.position.setFromMatrixPosition(A.matrixWorld);r.setFromMatrixPosition(A.target.matrixWorld);G.lookAt(r);G.updateMatrixWorld();G.matrixWorldInverse.getInverse(G.matrixWorld);A.cameraHelper&& +(A.cameraHelper.visible=A.shadowCameraVisible);A.shadowCameraVisible&&A.cameraHelper.update();F.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1);F.multiply(G.projectionMatrix);F.multiply(G.matrixWorldInverse);q.multiplyMatrices(G.projectionMatrix,G.matrixWorldInverse);p.setFromMatrix(q);a.setRenderTarget(E);a.clear();s.length=0;e(c,c,G);A=0;for(E=s.length;A 0 ) {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat fogFactor = 0.0;\nif ( fogType == 1 ) {\nfogFactor = smoothstep( fogNear, fogFar, depth );\n} else {\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n}\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );\n}\n}"].join("\n")); +w.compileShader(L);w.compileShader(P);w.attachShader(H,L);w.attachShader(H,P);w.linkProgram(H);E=H;v=w.getAttribLocation(E,"position");x=w.getAttribLocation(E,"uv");c=w.getUniformLocation(E,"uvOffset");d=w.getUniformLocation(E,"uvScale");e=w.getUniformLocation(E,"rotation");f=w.getUniformLocation(E,"scale");g=w.getUniformLocation(E,"color");h=w.getUniformLocation(E,"map");k=w.getUniformLocation(E,"opacity");l=w.getUniformLocation(E,"modelViewMatrix");p=w.getUniformLocation(E,"projectionMatrix");q= +w.getUniformLocation(E,"fogType");n=w.getUniformLocation(E,"fogDensity");t=w.getUniformLocation(E,"fogNear");r=w.getUniformLocation(E,"fogFar");s=w.getUniformLocation(E,"fogColor");u=w.getUniformLocation(E,"alphaTest");H=document.createElement("canvas");H.width=8;H.height=8;L=H.getContext("2d");L.fillStyle="white";L.fillRect(0,0,8,8);G=new THREE.Texture(H);G.needsUpdate=!0}w.useProgram(E);w.enableVertexAttribArray(v);w.enableVertexAttribArray(x);w.disable(w.CULL_FACE);w.enable(w.BLEND);w.bindBuffer(w.ARRAY_BUFFER, +y);w.vertexAttribPointer(v,2,w.FLOAT,!1,16,0);w.vertexAttribPointer(x,2,w.FLOAT,!1,16,8);w.bindBuffer(w.ELEMENT_ARRAY_BUFFER,A);w.uniformMatrix4fv(p,!1,M.projectionMatrix.elements);w.activeTexture(w.TEXTURE0);w.uniform1i(h,0);L=H=0;(P=U.fog)?(w.uniform3f(s,P.color.r,P.color.g,P.color.b),P instanceof THREE.Fog?(w.uniform1f(t,P.near),w.uniform1f(r,P.far),w.uniform1i(q,1),L=H=1):P instanceof THREE.FogExp2&&(w.uniform1f(n,P.density),w.uniform1i(q,2),L=H=2)):(w.uniform1i(q,0),L=H=0);for(var P=0,N=b.length;P< +N;P++){var R=b[P];R._modelViewMatrix.multiplyMatrices(M.matrixWorldInverse,R.matrixWorld);R.z=-R._modelViewMatrix.elements[14]}b.sort(D);for(var V=[],P=0,N=b.length;Pq-1?0:q-1,t=q+1>e-1?e-1:q+1,s=0>p-1?0:p-1,r=p+1>d-1?d-1:p+1,u=[],v=[0,0,h[4*(q*d+p)]/255*b];u.push([-1,0,h[4*(q*d+s)]/255*b]);u.push([-1,-1,h[4*(m*d+s)]/255*b]);u.push([0,-1,h[4*(m*d+p)]/255*b]);u.push([1,-1,h[4*(m*d+r)]/255*b]);u.push([1,0,h[4*(q*d+r)]/255*b]);u.push([1,1,h[4*(t*d+r)]/255*b]);u.push([0,1,h[4*(t*d+p)]/255* -b]);u.push([-1,1,h[4*(t*d+s)]/255*b]);m=[];s=u.length;for(t=0;tq-1?0:q-1,t=q+1>e-1?e-1:q+1,r=0>p-1?0:p-1,s=p+1>d-1?d-1:p+1,u=[],v=[0,0,h[4*(q*d+p)]/255*b];u.push([-1,0,h[4*(q*d+r)]/255*b]);u.push([-1,-1,h[4*(n*d+r)]/255*b]);u.push([0,-1,h[4*(n*d+p)]/255*b]);u.push([1,-1,h[4*(n*d+s)]/255*b]);u.push([1,0,h[4*(q*d+s)]/255*b]);u.push([1,1,h[4*(t*d+s)]/255*b]);u.push([0,1,h[4*(t*d+p)]/255* +b]);u.push([-1,1,h[4*(t*d+r)]/255*b]);n=[];r=u.length;for(t=0;te)return null;var f=[],g=[],h=[],k,n,p;if(0=q--){console.log("Warning, unable to triangulate polygon!");break}k=n;e<=k&&(k=0);n=k+1;e<=n&&(n=0);p=n+1;e<=p&&(p=0);var m;a:{var t=m=void 0,s=void 0,r=void 0,u=void 0,v=void 0,y=void 0,C=void 0,x=void 0, -t=a[g[k]].x,s=a[g[k]].y,r=a[g[n]].x,u=a[g[n]].y,v=a[g[p]].x,y=a[g[p]].y;if(1E-10>(r-t)*(y-s)-(u-s)*(v-t))m=!1;else{var F=void 0,z=void 0,G=void 0,E=void 0,w=void 0,D=void 0,A=void 0,U=void 0,M=void 0,K=void 0,M=U=A=x=C=void 0,F=v-r,z=y-u,G=t-v,E=s-y,w=r-t,D=u-s;for(m=0;me)return null;var f=[],g=[],h=[],k,l,p;if(0=q--){THREE.warn("THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()");break}k=l;e<=k&&(k=0);l=k+1;e<=l&&(l=0);p=l+1;e<=p&&(p=0);var n;a:{var t=n=void 0,r=void 0,s=void 0, +u=void 0,v=void 0,x=void 0,D=void 0,w=void 0,t=a[g[k]].x,r=a[g[k]].y,s=a[g[l]].x,u=a[g[l]].y,v=a[g[p]].x,x=a[g[p]].y;if(1E-10>(s-t)*(x-r)-(u-r)*(v-t))n=!1;else{var y=void 0,A=void 0,E=void 0,G=void 0,F=void 0,z=void 0,I=void 0,U=void 0,M=void 0,H=void 0,M=U=I=w=D=void 0,y=v-s,A=x-u,E=t-v,G=r-x,F=s-t,z=u-r;for(n=0;nk)g=d+1;else if(0b&&(b=0);1=b)return b=c[a]-b,a=this.curves[a],b=1-b/a.getLength(),a.getPointAt(b);a++}return null};THREE.CurvePath.prototype.getLength=function(){var a=this.getCurveLengths();return a[a.length-1]}; THREE.CurvePath.prototype.getCurveLengths=function(){if(this.cacheLengths&&this.cacheLengths.length==this.curves.length)return this.cacheLengths;var a=[],b=0,c,d=this.curves.length;for(c=0;cb?b=h.x:h.xc?c=h.y:h.yd?d=h.z:h.zb?b=h.x:h.xc?c=h.y:h.yd?d=h.z:h.zMath.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; -THREE.Path.prototype.toShapes=function(a,b){function c(a){for(var b=[],c=0,d=a.length;cm&&(g=b[f],k=-k,h=b[e],m=-m),!(a.yh.y))if(a.y==g.y){if(a.x==g.x)return!0}else{e=m*(a.x-g.x)-k*(a.y-g.y);if(0==e)return!0;0>e||(d=!d)}}else if(a.y==g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<= -h.x))return!0}return d}var e=function(a){var b,c,d,e,f=[],g=new THREE.Path;b=0;for(c=a.length;bMath.abs(d.x-c[0].x)&&1E-10>Math.abs(d.y-c[0].y)&&c.splice(c.length-1,1);b&&c.push(c[0]);return c}; +THREE.Path.prototype.toShapes=function(a,b){function c(a){for(var b=[],c=0,d=a.length;cn&&(g=b[f],k=-k,h=b[e],n=-n),!(a.yh.y))if(a.y==g.y){if(a.x==g.x)return!0}else{e=n*(a.x-g.x)-k*(a.y-g.y);if(0==e)return!0;0>e||(d=!d)}}else if(a.y==g.y&&(h.x<=a.x&&a.x<=g.x||g.x<=a.x&&a.x<= +h.x))return!0}return d}var e=function(a){var b,c,d,e,f=[],g=new THREE.Path;b=0;for(c=a.length;bE||E>G)return[];k=n*p-k*q;if(0>k||k>G)return[]}else{if(0d?[]:k==d?g?[]:[f]:a<=d?[f,h]: -[f,n]}function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return 1E-10f&&(f=d);var g=a+1;g>d&&(g=0);d=e(h[a],h[f],h[g],k[b]);if(!d)return!1; -d=k.length-1;f=b-1;0>f&&(f=d);g=b+1;g>d&&(g=0);return(d=e(k[b],k[f],k[g],h[a]))?!0:!1}function f(a,b){var c,e;for(c=0;cK){console.log("Infinite Loop! Holes left:"+ -n.length+", Probably Hole outside Shape!");break}for(q=D;qh;h++)n=k[h].x+":"+k[h].y, -n=p[n],void 0!==n&&(k[h]=n);return q.concat()},isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},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){return 3*(1-a)*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)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.constructor=THREE.LineCurve;THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)};THREE.LineCurve.prototype.getTangent=function(a){return this.v2.clone().sub(this.v1).normalize()}; -THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.constructor=THREE.QuadraticBezierCurve;THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b=new THREE.Vector2;b.x=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return b}; -THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b=new THREE.Vector2;b.x=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);return b.normalize()};THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.CubicBezierCurve.prototype.constructor=THREE.CubicBezierCurve; -THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)};THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b}; -THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.constructor=THREE.SplineCurve; +THREE.Shape.Utils={triangulateShape:function(a,b){function c(a,b,c){return a.x!=b.x?a.xG||G>E)return[];k=l*p-k*q;if(0>k||k>E)return[]}else{if(0d?[]:k==d?f?[]:[g]:a<=d?[g,h]: +[g,l]}function e(a,b,c,d){var e=b.x-a.x,f=b.y-a.y;b=c.x-a.x;c=c.y-a.y;var g=d.x-a.x;d=d.y-a.y;a=e*c-f*b;e=e*d-f*g;return 1E-10f&&(f=d);var g=a+1;g>d&&(g=0);d=e(h[a],h[f],h[g],k[b]); +if(!d)return!1;d=k.length-1;f=b-1;0>f&&(f=d);g=b+1;g>d&&(g=0);return(d=e(k[b],k[f],k[g],h[a]))?!0:!1}function f(a,b){var c,e;for(c=0;c +H){console.log("Infinite Loop! Holes left:"+l.length+", Probably Hole outside Shape!");break}for(q=z;qh;h++)l=k[h].x+":"+k[h].y,l=p[l],void 0!==l&&(k[h]=l);return q.concat()},isClockWise:function(a){return 0>THREE.FontUtils.Triangulate.area(a)},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){return 3*(1-a)*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)}};THREE.LineCurve=function(a,b){this.v1=a;this.v2=b};THREE.LineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.LineCurve.prototype.constructor=THREE.LineCurve;THREE.LineCurve.prototype.getPoint=function(a){var b=this.v2.clone().sub(this.v1);b.multiplyScalar(a).add(this.v1);return b};THREE.LineCurve.prototype.getPointAt=function(a){return this.getPoint(a)}; +THREE.LineCurve.prototype.getTangent=function(a){return this.v2.clone().sub(this.v1).normalize()};THREE.QuadraticBezierCurve=function(a,b,c){this.v0=a;this.v1=b;this.v2=c};THREE.QuadraticBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.QuadraticBezierCurve.prototype.constructor=THREE.QuadraticBezierCurve; +THREE.QuadraticBezierCurve.prototype.getPoint=function(a){var b=new THREE.Vector2;b.x=THREE.Shape.Utils.b2(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Shape.Utils.b2(a,this.v0.y,this.v1.y,this.v2.y);return b};THREE.QuadraticBezierCurve.prototype.getTangent=function(a){var b=new THREE.Vector2;b.x=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.x,this.v1.x,this.v2.x);b.y=THREE.Curve.Utils.tangentQuadraticBezier(a,this.v0.y,this.v1.y,this.v2.y);return b.normalize()}; +THREE.CubicBezierCurve=function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d};THREE.CubicBezierCurve.prototype=Object.create(THREE.Curve.prototype);THREE.CubicBezierCurve.prototype.constructor=THREE.CubicBezierCurve;THREE.CubicBezierCurve.prototype.getPoint=function(a){var b;b=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);return new THREE.Vector2(b,a)}; +THREE.CubicBezierCurve.prototype.getTangent=function(a){var b;b=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);a=THREE.Curve.Utils.tangentCubicBezier(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b=new THREE.Vector2(b,a);b.normalize();return b};THREE.SplineCurve=function(a){this.points=void 0==a?[]:a};THREE.SplineCurve.prototype=Object.create(THREE.Curve.prototype);THREE.SplineCurve.prototype.constructor=THREE.SplineCurve; THREE.SplineCurve.prototype.getPoint=function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=new THREE.Vector2;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);return c};THREE.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}; THREE.EllipseCurve.prototype=Object.create(THREE.Curve.prototype);THREE.EllipseCurve.prototype.constructor=THREE.EllipseCurve;THREE.EllipseCurve.prototype.getPoint=function(a){var b=this.aEndAngle-this.aStartAngle;0>b&&(b+=2*Math.PI);b>2*Math.PI&&(b-=2*Math.PI);a=!0===this.aClockwise?this.aEndAngle+(1-a)*(2*Math.PI-b):this.aStartAngle+a*b;b=new THREE.Vector2;b.x=this.aX+this.xRadius*Math.cos(a);b.y=this.aY+this.yRadius*Math.sin(a);return b}; THREE.ArcCurve=function(a,b,c,d,e,f){THREE.EllipseCurve.call(this,a,b,c,c,d,e,f)};THREE.ArcCurve.prototype=Object.create(THREE.EllipseCurve.prototype);THREE.ArcCurve.prototype.constructor=THREE.ArcCurve;THREE.LineCurve3=THREE.Curve.create(function(a,b){this.v1=a;this.v2=b},function(a){var b=new THREE.Vector3;b.subVectors(this.v2,this.v1);b.multiplyScalar(a);b.add(this.v1);return b}); @@ -682,7 +693,7 @@ THREE.QuadraticBezierCurve3=THREE.Curve.create(function(a,b,c){this.v0=a;this.v1 THREE.CubicBezierCurve3=THREE.Curve.create(function(a,b,c,d){this.v0=a;this.v1=b;this.v2=c;this.v3=d},function(a){var b=new THREE.Vector3;b.x=THREE.Shape.Utils.b3(a,this.v0.x,this.v1.x,this.v2.x,this.v3.x);b.y=THREE.Shape.Utils.b3(a,this.v0.y,this.v1.y,this.v2.y,this.v3.y);b.z=THREE.Shape.Utils.b3(a,this.v0.z,this.v1.z,this.v2.z,this.v3.z);return b}); THREE.SplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-1;var c=Math.floor(a);a-=c;var d=b[0==c?c:c-1],e=b[c],f=b[c>b.length-2?b.length-1:c+1],b=b[c>b.length-3?b.length-1:c+2],c=new THREE.Vector3;c.x=THREE.Curve.Utils.interpolate(d.x,e.x,f.x,b.x,a);c.y=THREE.Curve.Utils.interpolate(d.y,e.y,f.y,b.y,a);c.z=THREE.Curve.Utils.interpolate(d.z,e.z,f.z,b.z,a);return c}); THREE.ClosedSplineCurve3=THREE.Curve.create(function(a){this.points=void 0==a?[]:a},function(a){var b=this.points;a*=b.length-0;var c=Math.floor(a);a-=c;var c=c+(0a.hierarchy[b].keys[c].time&&(a.hierarchy[b].keys[c].time= +THREE.AnimationHandler={LINEAR:0,CATMULLROM:1,CATMULLROM_FORWARD:2,add:function(){THREE.warn("THREE.AnimationHandler.add() has been deprecated.")},get:function(){THREE.warn("THREE.AnimationHandler.get() has been deprecated.")},remove:function(){THREE.warn("THREE.AnimationHandler.remove() has been deprecated.")},animations:[],init:function(a){if(!0===a.initialized)return a;for(var b=0;ba.hierarchy[b].keys[c].time&&(a.hierarchy[b].keys[c].time= 0),void 0!==a.hierarchy[b].keys[c].rot&&!(a.hierarchy[b].keys[c].rot instanceof THREE.Quaternion)){var d=a.hierarchy[b].keys[c].rot;a.hierarchy[b].keys[c].rot=(new THREE.Quaternion).fromArray(d)}if(a.hierarchy[b].keys.length&&void 0!==a.hierarchy[b].keys[0].morphTargets){d={};for(c=0;cd;d++){for(var e=this.keyTypes[d],f=this.data.hierarchy[a].keys[0],g=this.getNextKeyWith(e,a,1);g.timef.index;)f=g,g=this.getNextKeyWith(e,a,g.index+1);c.prevKey[e]=f;c.nextKey[e]=g}}}; THREE.Animation.prototype.resetBlendWeights=function(){for(var a=0,b=this.hierarchy.length;aa.length-2?q:q+1;c[3]=q>a.length-3?q:q+2;q=a[c[0]];t=a[c[1]];s=a[c[2]];r=a[c[3]];c=e*e;m=e*c;d[0]=f(q[0],t[0],s[0],r[0],e,c,m);d[1]=f(q[1],t[1],s[1],r[1],e,c,m);d[2]=f(q[2],t[2],s[2],r[2],e,c,m);return d},f=function(a,b,c,d,e,f,m){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*m+ -(-3*(b-c)-2*a-d)*f+a*e+b};return function(f){if(!1!==this.isPlaying&&(this.currentTime+=f*this.timeScale,0!==this.weight)){f=this.data.length;if(this.currentTime>f||0>this.currentTime)this.loop?(this.currentTime%=f,0>this.currentTime&&(this.currentTime+=f),this.reset()):this.stop();f=0;for(var h=this.hierarchy.length;fq;q++){var m=this.keyTypes[q],t=n.prevKey[m],s=n.nextKey[m];if(0this.timeScale&&t.time>=this.currentTime){t=this.data.hierarchy[f].keys[0];for(s=this.getNextKeyWith(m,f,1);s.timet.index;)t=s,s=this.getNextKeyWith(m,f,s.index+1);n.prevKey[m]=t;n.nextKey[m]=s}var r=(this.currentTime-t.time)/(s.time-t.time),u=t[m],v=s[m];0>r&&(r=0);1a.length-2?q:q+1;c[3]=q>a.length-3?q:q+2;q=a[c[0]];t=a[c[1]];r=a[c[2]];s=a[c[3]];c=e*e;n=e*c;d[0]=f(q[0],t[0],r[0],s[0],e,c,n);d[1]=f(q[1],t[1],r[1],s[1],e,c,n);d[2]=f(q[2],t[2],r[2],s[2],e,c,n);return d},f=function(a,b,c,d,e,f,n){a=.5*(c-a);d=.5*(d-b);return(2*(b-c)+a+d)*n+ +(-3*(b-c)-2*a-d)*f+a*e+b};return function(f){if(!1!==this.isPlaying&&(this.currentTime+=f*this.timeScale,0!==this.weight)){f=this.data.length;if(this.currentTime>f||0>this.currentTime)this.loop?(this.currentTime%=f,0>this.currentTime&&(this.currentTime+=f),this.reset()):this.stop();f=0;for(var h=this.hierarchy.length;fq;q++){var n=this.keyTypes[q],t=l.prevKey[n],r=l.nextKey[n];if(0this.timeScale&&t.time>=this.currentTime){t=this.data.hierarchy[f].keys[0];for(r=this.getNextKeyWith(n,f,1);r.timet.index;)t=r,r=this.getNextKeyWith(n,f,r.index+1);l.prevKey[n]=t;l.nextKey[n]=r}var s=(this.currentTime-t.time)/(r.time-t.time),u=t[n],v=r[n];0>s&&(s=0);1=this.currentTime?f.interpolate(g,this.currentTime):f.inter THREE.KeyFrameAnimation.prototype.getPrevKeyWith=function(a,b,c){b=this.data.hierarchy[b].keys;for(c=0<=c?c:c+b.length;0<=c;c--)if(b[c].hasTarget(a))return b[c];return b[b.length-1]};THREE.MorphAnimation=function(a){this.mesh=a;this.frames=a.morphTargetInfluences.length;this.currentTime=0;this.duration=1E3;this.loop=!0;this.currentFrame=this.lastFrame=0;this.isPlaying=!1}; THREE.MorphAnimation.prototype={constructor:THREE.MorphAnimation,play:function(){this.isPlaying=!0},pause:function(){this.isPlaying=!1},update:function(a){if(!1!==this.isPlaying){this.currentTime+=a;!0===this.loop&&this.currentTime>this.duration&&(this.currentTime%=this.duration);this.currentTime=Math.min(this.currentTime,this.duration);a=this.duration/this.frames;var b=Math.floor(this.currentTime/a);b!=this.currentFrame&&(this.mesh.morphTargetInfluences[this.lastFrame]=0,this.mesh.morphTargetInfluences[this.currentFrame]= 1,this.mesh.morphTargetInfluences[b]=0,this.lastFrame=this.currentFrame,this.currentFrame=b);this.mesh.morphTargetInfluences[b]=this.currentTime%a/a;this.mesh.morphTargetInfluences[this.lastFrame]=1-this.mesh.morphTargetInfluences[b]}}}; -THREE.BoxGeometry=function(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,r){var u,v=h.widthSegments,y=h.heightSegments,C=e/2,x=f/2,F=h.vertices.length;if("x"===a&&"y"===b||"y"===a&&"x"===b)u="z";else if("x"===a&&"z"===b||"z"===a&&"x"===b)u="y",y=h.depthSegments;else if("z"===a&&"y"===b||"y"===a&&"z"===b)u="x",v=h.depthSegments;var z=v+1,G=y+1,E=e/v,w=f/y,D=new THREE.Vector3;D[u]=0=d)return new THREE.Vector2(c,a);d=Math.sqrt(d/2)}else a=!1,1E-10d?-1E-10>f&&(a=!0):Math.sign(e)== -Math.sign(g)&&(a=!0),a?(c=-e,a=d,d=Math.sqrt(h)):(c=d,a=e,d=Math.sqrt(h/2));return new THREE.Vector2(c/d,a/d)}function e(a,b){var c,d;for(H=a.length;0<=--H;){c=H;d=H-1;0>d&&(d=a.length-1);for(var e=0,f=t+2*p,e=0;e=d)return new THREE.Vector2(c,a);d=Math.sqrt(d/2)}else a=!1,1E-10d?-1E-10>f&&(a=!0):Math.sign(e)==Math.sign(g)&&(a=!0),a?(c=-e,a=d,d=Math.sqrt(h)):(c=d,a=e,d=Math.sqrt(h/2));return new THREE.Vector2(c/d,a/d)}function e(a,b){var c,d;for(O=a.length;0<=--O;){c=O;d=O-1;0>d&&(d=a.length-1);for(var e=0,f=t+2*p,e=0;eMath.abs(b.y-c.y)?[new THREE.Vector2(b.x,1-b.z),new THREE.Vector2(c.x,1-c.z),new THREE.Vector2(d.x,1-d.z),new THREE.Vector2(e.x,1-e.z)]:[new THREE.Vector2(b.y,1-b.z),new THREE.Vector2(c.y,1-c.z),new THREE.Vector2(d.y, 1-d.z),new THREE.Vector2(e.y,1-e.z)]}};THREE.ShapeGeometry=function(a,b){THREE.Geometry.call(this);this.type="ShapeGeometry";!1===a instanceof Array&&(a=[a]);this.addShapeList(a,b);this.computeFaceNormals()};THREE.ShapeGeometry.prototype=Object.create(THREE.Geometry.prototype);THREE.ShapeGeometry.prototype.constructor=THREE.ShapeGeometry;THREE.ShapeGeometry.prototype.addShapeList=function(a,b){for(var c=0,d=a.length;cc&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+.5, -a.y));return a.clone()}THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var k=this,n=0,p=a.length;nt&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>q&&(b[2].x+=1));n=0;for(p=this.vertices.length;nc&&1===a.x&&(a=new THREE.Vector2(a.x-1,a.y));0===b.x&&0===b.z&&(a=new THREE.Vector2(c/2/Math.PI+.5,a.y));return a.clone()} +THREE.Geometry.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;for(var k=this,l=0,p=a.length;lt&&(.2>d&&(b[0].x+=1),.2>a&&(b[1].x+=1),.2>q&&(b[2].x+=1));l=0;for(p=this.vertices.length;ls;s++){d[0]=t[g[s]];d[1]=t[g[(s+1)%3]];d.sort(f);var r=d.toString();void 0===e[r]?(e[r]={vert1:d[0],vert2:d[1],face1:q,face2:void 0},p++):e[r].face2=q}d=new Float32Array(6*p);f=0;for(r in e)if(g=e[r],void 0===g.face2|| -.9999>k[g.face1].normal.dot(k[g.face2].normal))p=n[g.vert1],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z,p=n[g.vert2],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3));THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.EdgesHelper.prototype=Object.create(THREE.Line.prototype);THREE.EdgesHelper.prototype.constructor=THREE.EdgesHelper; +THREE.EdgesHelper=function(a,b,c){b=void 0!==b?b:16777215;c=Math.cos(THREE.Math.degToRad(void 0!==c?c:1));var d=[0,0],e={},f=function(a,b){return a-b},g=["a","b","c"],h=new THREE.BufferGeometry,k;a.geometry instanceof THREE.BufferGeometry?(k=new THREE.Geometry,k.fromBufferGeometry(a.geometry)):k=a.geometry.clone();k.mergeVertices();k.computeFaceNormals();var l=k.vertices;k=k.faces;for(var p=0,q=0,n=k.length;qr;r++){d[0]=t[g[r]];d[1]=t[g[(r+1)%3]];d.sort(f);var s=d.toString(); +void 0===e[s]?(e[s]={vert1:d[0],vert2:d[1],face1:q,face2:void 0},p++):e[s].face2=q}d=new Float32Array(6*p);f=0;for(s in e)if(g=e[s],void 0===g.face2||k[g.face1].normal.dot(k[g.face2].normal)<=c)p=l[g.vert1],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z,p=l[g.vert2],d[f++]=p.x,d[f++]=p.y,d[f++]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3));THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:b}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1}; +THREE.EdgesHelper.prototype=Object.create(THREE.Line.prototype);THREE.EdgesHelper.prototype.constructor=THREE.EdgesHelper; THREE.FaceNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;a=void 0!==c?c:16776960;d=void 0!==d?d:1;b=new THREE.Geometry;c=0;for(var e=this.object.geometry.faces.length;cb;b++)a.faces[b].color=this.colors[4>b?0:1];b=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(a,b);this.add(this.lightSphere); +THREE.HemisphereLightHelper=function(a,b){THREE.Object3D.call(this);this.light=a;this.light.updateMatrixWorld();this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1;this.colors=[new THREE.Color,new THREE.Color];var c=new THREE.SphereGeometry(b,4,2);c.applyMatrix((new THREE.Matrix4).makeRotationX(-Math.PI/2));for(var d=0;8>d;d++)c.faces[d].color=this.colors[4>d?0:1];d=new THREE.MeshBasicMaterial({vertexColors:THREE.FaceColors,wireframe:!0});this.lightSphere=new THREE.Mesh(c,d);this.add(this.lightSphere); this.update()};THREE.HemisphereLightHelper.prototype=Object.create(THREE.Object3D.prototype);THREE.HemisphereLightHelper.prototype.constructor=THREE.HemisphereLightHelper;THREE.HemisphereLightHelper.prototype.dispose=function(){this.lightSphere.geometry.dispose();this.lightSphere.material.dispose()}; THREE.HemisphereLightHelper.prototype.update=function(){var a=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(a.setFromMatrixPosition(this.light.matrixWorld).negate());this.lightSphere.geometry.colorsNeedUpdate=!0}}(); THREE.PointLightHelper=function(a,b){this.light=a;this.light.updateMatrixWorld();var c=new THREE.SphereGeometry(b,4,2),d=new THREE.MeshBasicMaterial({wireframe:!0,fog:!1});d.color.copy(this.light.color).multiplyScalar(this.light.intensity);THREE.Mesh.call(this,c,d);this.matrix=this.light.matrixWorld;this.matrixAutoUpdate=!1};THREE.PointLightHelper.prototype=Object.create(THREE.Mesh.prototype);THREE.PointLightHelper.prototype.constructor=THREE.PointLightHelper; @@ -806,21 +817,21 @@ THREE.SpotLightHelper.prototype.constructor=THREE.SpotLightHelper;THREE.SpotLigh THREE.SpotLightHelper.prototype.update=function(){var a=new THREE.Vector3,b=new THREE.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)}}(); THREE.VertexNormalsHelper=function(a,b,c,d){this.object=a;this.size=void 0!==b?b:1;b=void 0!==c?c:16711680;d=void 0!==d?d:1;c=new THREE.Geometry;a=a.geometry.faces;for(var e=0,f=a.length;er;r++){d[0]=s[g[r]];d[1]=s[g[(r+1)%3]];d.sort(f);var u=d.toString();void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++)}d=new Float32Array(6*p);m=0;for(t=p;mr;r++)p= -k[q[2*m+r]],g=6*m+3*r,d[g+0]=p.x,d[g+1]=p.y,d[g+2]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3))}else if(a.geometry instanceof THREE.BufferGeometry){if(void 0!==a.geometry.attributes.index){k=a.geometry.attributes.position.array;t=a.geometry.attributes.index.array;n=a.geometry.drawcalls;p=0;0===n.length&&(n=[{count:t.length,index:0,start:0}]);for(var q=new Uint32Array(2*t.length),s=0,v=n.length;sr;r++)d[0]= -g+t[m+r],d[1]=g+t[m+(r+1)%3],d.sort(f),u=d.toString(),void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++);d=new Float32Array(6*p);m=0;for(t=p;mr;r++)g=6*m+3*r,p=3*q[2*m+r],d[g+0]=k[p],d[g+1]=k[p+1],d[g+2]=k[p+2]}else for(k=a.geometry.attributes.position.array,p=k.length/3,q=p/3,d=new Float32Array(6*p),m=0,t=q;mr;r++)g=18*m+6*r,q=9*m+3*r,d[g+0]=k[q],d[g+1]=k[q+1],d[g+2]=k[q+2],p=9*m+(r+1)%3*3,d[g+3]=k[p],d[g+4]=k[p+1],d[g+5]=k[p+2];h.addAttribute("position",new THREE.BufferAttribute(d, +THREE.WireframeHelper=function(a,b){var c=void 0!==b?b:16777215,d=[0,0],e={},f=function(a,b){return a-b},g=["a","b","c"],h=new THREE.BufferGeometry;if(a.geometry instanceof THREE.Geometry){for(var k=a.geometry.vertices,l=a.geometry.faces,p=0,q=new Uint32Array(6*l.length),n=0,t=l.length;ns;s++){d[0]=r[g[s]];d[1]=r[g[(s+1)%3]];d.sort(f);var u=d.toString();void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++)}d=new Float32Array(6*p);n=0;for(t=p;ns;s++)p= +k[q[2*n+s]],g=6*n+3*s,d[g+0]=p.x,d[g+1]=p.y,d[g+2]=p.z;h.addAttribute("position",new THREE.BufferAttribute(d,3))}else if(a.geometry instanceof THREE.BufferGeometry){if(void 0!==a.geometry.attributes.index){k=a.geometry.attributes.position.array;t=a.geometry.attributes.index.array;l=a.geometry.drawcalls;p=0;0===l.length&&(l=[{count:t.length,index:0,start:0}]);for(var q=new Uint32Array(2*t.length),r=0,v=l.length;rs;s++)d[0]= +g+t[n+s],d[1]=g+t[n+(s+1)%3],d.sort(f),u=d.toString(),void 0===e[u]&&(q[2*p]=d[0],q[2*p+1]=d[1],e[u]=!0,p++);d=new Float32Array(6*p);n=0;for(t=p;ns;s++)g=6*n+3*s,p=3*q[2*n+s],d[g+0]=k[p],d[g+1]=k[p+1],d[g+2]=k[p+2]}else for(k=a.geometry.attributes.position.array,p=k.length/3,q=p/3,d=new Float32Array(6*p),n=0,t=q;ns;s++)g=18*n+6*s,q=9*n+3*s,d[g+0]=k[q],d[g+1]=k[q+1],d[g+2]=k[q+2],p=9*n+(s+1)%3*3,d[g+3]=k[p],d[g+4]=k[p+1],d[g+5]=k[p+2];h.addAttribute("position",new THREE.BufferAttribute(d, 3))}THREE.Line.call(this,h,new THREE.LineBasicMaterial({color:c}),THREE.LinePieces);this.matrix=a.matrixWorld;this.matrixAutoUpdate=!1};THREE.WireframeHelper.prototype=Object.create(THREE.Line.prototype);THREE.WireframeHelper.prototype.constructor=THREE.WireframeHelper;THREE.ImmediateRenderObject=function(){THREE.Object3D.call(this);this.render=function(a){}};THREE.ImmediateRenderObject.prototype=Object.create(THREE.Object3D.prototype);THREE.ImmediateRenderObject.prototype.constructor=THREE.ImmediateRenderObject; THREE.MorphBlendMesh=function(a,b){THREE.Mesh.call(this,a,b);this.animationsMap={};this.animationsList=[];var c=this.geometry.morphTargets.length;this.createAnimation("__default",0,c-1,c/1);this.setAnimationWeight("__default",1)};THREE.MorphBlendMesh.prototype=Object.create(THREE.Mesh.prototype);THREE.MorphBlendMesh.prototype.constructor=THREE.MorphBlendMesh; THREE.MorphBlendMesh.prototype.createAnimation=function(a,b,c,d){b={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]=b;this.animationsList.push(b)}; THREE.MorphBlendMesh.prototype.autoCreateAnimations=function(a){for(var b=/([a-z]+)_?(\d+)/,c,d={},e=this.geometry,f=0,g=e.morphTargets.length;fh.end&&(h.end=f);c||(c=k)}}for(k in d)h=d[k],this.createAnimation(k,h.start,h.end,a);this.firstAnimation=c}; THREE.MorphBlendMesh.prototype.setAnimationDirectionForward=function(a){if(a=this.animationsMap[a])a.direction=1,a.directionBackwards=!1};THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward=function(a){if(a=this.animationsMap[a])a.direction=-1,a.directionBackwards=!0};THREE.MorphBlendMesh.prototype.setAnimationFPS=function(a,b){var c=this.animationsMap[a];c&&(c.fps=b,c.duration=(c.end-c.start)/c.fps)}; THREE.MorphBlendMesh.prototype.setAnimationDuration=function(a,b){var c=this.animationsMap[a];c&&(c.duration=b,c.fps=(c.end-c.start)/c.duration)};THREE.MorphBlendMesh.prototype.setAnimationWeight=function(a,b){var c=this.animationsMap[a];c&&(c.weight=b)};THREE.MorphBlendMesh.prototype.setAnimationTime=function(a,b){var c=this.animationsMap[a];c&&(c.time=b)};THREE.MorphBlendMesh.prototype.getAnimationTime=function(a){var b=0;if(a=this.animationsMap[a])b=a.time;return b}; -THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):console.warn("animation["+a+"] undefined")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; +THREE.MorphBlendMesh.prototype.getAnimationDuration=function(a){var b=-1;if(a=this.animationsMap[a])b=a.duration;return b};THREE.MorphBlendMesh.prototype.playAnimation=function(a){var b=this.animationsMap[a];b?(b.time=0,b.active=!0):THREE.warn("THREE.MorphBlendMesh: animation["+a+"] undefined in .playAnimation()")};THREE.MorphBlendMesh.prototype.stopAnimation=function(a){if(a=this.animationsMap[a])a.active=!1}; THREE.MorphBlendMesh.prototype.update=function(a){for(var b=0,c=this.animationsList.length;bd.duration||0>d.time)d.direction*=-1,d.time>d.duration&&(d.time=d.duration,d.directionBackwards=!0),0>d.time&&(d.time=0,d.directionBackwards=!1)}else d.time%=d.duration,0>d.time&&(d.time+=d.duration);var f=d.startFrame+THREE.Math.clamp(Math.floor(d.time/e),0,d.length-1),g=d.weight; f!==d.currentFrame&&(this.morphTargetInfluences[d.lastFrame]=0,this.morphTargetInfluences[d.currentFrame]=1*g,this.morphTargetInfluences[f]=0,d.lastFrame=d.currentFrame,d.currentFrame=f);e=d.time%e/e;d.directionBackwards&&(e=1-e);this.morphTargetInfluences[d.currentFrame]=e*g;this.morphTargetInfluences[d.lastFrame]=(1-e)*g}}}; diff --git a/docs/api/cameras/CubeCamera.html b/docs/api/cameras/CubeCamera.html index f51201bdc61498..d4170ab9398edf 100644 --- a/docs/api/cameras/CubeCamera.html +++ b/docs/api/cameras/CubeCamera.html @@ -24,7 +24,7 @@

Examples

scene.add( cubeCamera ); //Create car - var chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, ambient: 0xffffff, envMap: cubeCamera.renderTarget } ); + var chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: cubeCamera.renderTarget } ); var car = new Mesh( carGeometry, chromeMaterial ); scene.add( car ); diff --git a/docs/api/constants/CustomBlendingEquations.html b/docs/api/constants/CustomBlendingEquations.html index b27f99eb9a5708..bee4aae4586394 100644 --- a/docs/api/constants/CustomBlendingEquations.html +++ b/docs/api/constants/CustomBlendingEquations.html @@ -13,7 +13,9 @@

Equations

THREE.AddEquation
THREE.SubtractEquation
- THREE.ReverseSubtractEquation + THREE.ReverseSubtractEquation
+ THREE.MinEquation
+ THREE.MaxEquation

Destination Factors

diff --git a/docs/api/constants/GLState.html b/docs/api/constants/GLState.html index f75843f14fbd58..06e08e5c8dabb3 100644 --- a/docs/api/constants/GLState.html +++ b/docs/api/constants/GLState.html @@ -7,7 +7,7 @@ -

GL State Conflicts

+

GL State Constants

Cull Face

diff --git a/docs/api/constants/Textures.html b/docs/api/constants/Textures.html index 4bc5587aa7a5fc..165604b3b457ce 100644 --- a/docs/api/constants/Textures.html +++ b/docs/api/constants/Textures.html @@ -21,6 +21,8 @@

Mapping Modes

THREE.UVMapping
THREE.CubeReflectionMapping
THREE.CubeRefractionMapping
+ THREE.EquirectangularReflectionMapping
+ THREE.EquirectangularRefractionMapping
THREE.SphericalReflectionMapping
@@ -49,7 +51,8 @@

Data Types

THREE.UnsignedShortType
THREE.IntType
THREE.UnsignedIntType
- THREE.FloatType + THREE.FloatType
+ THREE.HalfFloatType

Pixel Types

@@ -65,10 +68,11 @@

Pixel Formats

THREE.RGBFormat
THREE.RGBAFormat
THREE.LuminanceFormat
- THREE.LuminanceAlphaFormat + THREE.LuminanceAlphaFormat
+ THREE.RGBEFormat -

Compressed Texture Formats

+

DDS / ST3C Compressed Texture Formats

THREE.RGB_S3TC_DXT1_Format
THREE.RGBA_S3TC_DXT1_Format
@@ -76,6 +80,13 @@

Compressed Texture Formats

THREE.RGBA_S3TC_DXT5_Format
+

PVRTC Compressed Texture Formats

+
+ THREE.RGB_PVRTC_4BPPV1_Format
+ THREE.RGB_PVRTC_2BPPV1_Format
+ THREE.RGBA_PVRTC_4BPPV1_Format
+ THREE.RGBA_PVRTC_2BPPV1_Format +

Source

diff --git a/docs/api/core/Raycaster.html b/docs/api/core/Raycaster.html index b06160765f0b13..ce6b442c41308b 100644 --- a/docs/api/core/Raycaster.html +++ b/docs/api/core/Raycaster.html @@ -23,8 +23,8 @@

Example

// calculate mouse position in normalized device coordinates // (-1 to +1) for both components - mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1 - mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1 + mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; + mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; } @@ -36,9 +36,9 @@

Example

// calculate objects intersecting the picking ray var intersects = raycaster.intersectObjects( scene.children ); - for ( var intersect in intersects ) { + for ( var i = 0; i < intersects.length; i++ ) { - intersect.object.material.color = new THREE.Color( 0xff0000 ); + intersects[ i ].object.material.color.set( 0xff0000 ); } diff --git a/docs/api/extras/geometries/CylinderGeometry.html b/docs/api/extras/geometries/CylinderGeometry.html index 51e6803ca3c282..e17b611ac9c7c8 100644 --- a/docs/api/extras/geometries/CylinderGeometry.html +++ b/docs/api/extras/geometries/CylinderGeometry.html @@ -8,7 +8,7 @@ [page:Geometry] → - +

[name]

A class for generating cylinder geometries
@@ -26,21 +26,23 @@

Example

Constructor

-

[name]([page:Float radiusTop], [page:Float radiusBottom], [page:Float height], [page:Integer radiusSegments], [page:Integer heightSegments], [page:Boolean openEnded])

+

[name]([page:Float radiusTop], [page:Float radiusBottom], [page:Float height], [page:Integer radiusSegments], [page:Integer heightSegments], [page:Boolean openEnded], [page:Float thetaStart], [page:Float thetaLength])

radiusTop — Radius of the cylinder at the top. Default is 20.
radiusBottom — Radius of the cylinder at the bottom. Default is 20.
height — Height of the cylinder. Default is 100.
radiusSegments — Number of segmented faces around the circumference of the cylinder. Default is 8
heightSegments — Number of rows of faces along the height of the cylinder. Default is 1.
- openEnded — A Boolean indicating whether the ends of the cylinder are open or capped. Default is false, meaning capped. + openEnded — A Boolean indicating whether the ends of the cylinder are open or capped. Default is false, meaning capped.
+ thetaStart — Start angle for first segment, default = 0 (three o'clock position).
+ thetaLength — The central angle, often called theta, of the circular sector. The default is 2*Pi, which makes for a complete cylinder.

Properties

- Each of the contructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry. + Each of the constructor parameters is accessible as a property of the same name. Any modification of these properties after instantiation does not change the geometry.
diff --git a/docs/api/extras/helpers/CameraHelper.html b/docs/api/extras/helpers/CameraHelper.html index 1a6fd9f1f246bc..64d74380d55082 100644 --- a/docs/api/extras/helpers/CameraHelper.html +++ b/docs/api/extras/helpers/CameraHelper.html @@ -45,7 +45,7 @@

[property:Camera camera]

Methods

-

[method:todo update]()

+

[method:null update]()

Updates the helper based on the projectionMatrix of the camera.
diff --git a/docs/api/extras/helpers/DirectionalLightHelper.html b/docs/api/extras/helpers/DirectionalLightHelper.html index 4b1d62f0972d96..80aa9e095a4e4c 100644 --- a/docs/api/extras/helpers/DirectionalLightHelper.html +++ b/docs/api/extras/helpers/DirectionalLightHelper.html @@ -17,7 +17,7 @@

[name]

Constructor

-

[name]([DirectionalLight:todo light], [page:Number size])

+

[name]([page:DirectionalLight light], [page:Number size])

light -- [page:DirectionalLight] -- Light to visualize
size -- dimensions of the plane @@ -32,18 +32,18 @@

Properties

[property:Line lightPlane]

- todo + Contains the line mesh showing the location of the directional light.

[property:DirectionalLight light]

- todo + Contains the directionalLight.

[property:Line targetLine]

- todo -
+ Contains the line mesh that shows the direction of the light. +

Methods

diff --git a/docs/api/extras/helpers/EdgesHelper.html b/docs/api/extras/helpers/EdgesHelper.html index 69f99bfc0c3223..d3b11734d3ee23 100644 --- a/docs/api/extras/helpers/EdgesHelper.html +++ b/docs/api/extras/helpers/EdgesHelper.html @@ -27,10 +27,12 @@

Example

Constructor

-

[name]( [page:Object3D object], [page:Color color] )

+

[name]( [page:Object3D object], [page:Color color], [page:Float thresholdAngle] )

object -- Object of which to draw edges
- color -- Color of the edges. + color -- Color of the edges.
+ thresholdAngle -- the minimim angle (in degrees), between the face normals of adjacent faces, that is required to render an edge. Default is 0.1. +
Creates a [page:Line], showing only the "hard" edges of the passed object; specifically, no edge will be drawn between faces which are adjacent and coplanar (or nearly coplanar). diff --git a/docs/api/extras/helpers/HemisphereLightHelper.html b/docs/api/extras/helpers/HemisphereLightHelper.html index 52987be41530bd..070a2ae2735941 100644 --- a/docs/api/extras/helpers/HemisphereLightHelper.html +++ b/docs/api/extras/helpers/HemisphereLightHelper.html @@ -11,20 +11,18 @@

[name]

-
todo
+
Creates a visual aid for a [page:HemisphereLight HemisphereLight].

Constructor

-

[name]([page:todo light], [page:todo sphereSize], [page:todo arrowLength], [page:todo domeSize])

+

[name]([page:HemisphereLight light], [page:Number sphereSize])

- light -- todo
- sphereSize -- todo
- arrowLength -- todo
- domeSize -- todo + light -- The HemisphereLight.
+ sphereSize -- The size of the sphere that shows the location.
- todo + Creates an helper for the hemispherelight.
@@ -32,20 +30,20 @@

Properties

[property:Mesh lightSphere]

- todo + The sphere mesh that shows the location of the hemispherelight.

[property:HemisphereLight light]

- todo + Contains the HemisphereLight.

Methods

-

[method:todo update]()

+

[method:null update]()

- todo + Updates the helper to match the position and direction of the [page:.light].
diff --git a/docs/api/loaders/OBJMTLLoader.html b/docs/api/loaders/OBJMTLLoader.html index e87c1a283d94f7..31b7ca94dbc5ad 100644 --- a/docs/api/loaders/OBJMTLLoader.html +++ b/docs/api/loaders/OBJMTLLoader.html @@ -47,7 +47,7 @@

[method:Object3D parse]( [page:String text], [page:Function mtllibCallback]

Parse an obj text structure and return an [page:Object3D].
- Found objects are converted to [page:Mesh] with a [page:BufferGeometry] and materials are converted to [page:MeshLambertMaterial]. + Found objects are converted to a [page:Mesh] and materials are converted to [page:MeshLambertMaterial].

Example

diff --git a/docs/api/loaders/SceneLoader.html b/docs/api/loaders/SceneLoader.html deleted file mode 100644 index b7a169a9cdeeca..00000000000000 --- a/docs/api/loaders/SceneLoader.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - -

[name]

- -
A loader for loading a [page:Scene] from a JSON resource.
- - -

Constructor

- -

[name]( [page:LoadingManager manager] )

-
- [page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager]. -
-
- Creates a new [name]. -
- -

Properties

- - -

Methods

- -

[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )

-
- [page:String url] — required
- [page:Function onLoad] — Will be called when load completes. The argument will be an [page:Object] containing the loaded components.
- [page:Function onProgress] — Will be called while load progresses. The argument will be the XmlHttpRequest instance, that contain .[page:Integer total] and .[page:Integer loaded] bytes.
- [page:Function onError] — Will be called when load errors.
-
-
- Begin loading from url and call onLoad with the parsed scene. -
- -

[method:Object parse]( [page:Object json], [page:Function callbackFinished], [page:String url] )

-
- [page:Object json] — The JSON structure to parse.
- [page:Function callbackFinished] — Will be called when parse completes.
- [page:String url] — Will be used as base for assets' relative URLs.
-
-
- Parse a JSON scene description and return a new [page:Object] with fully instantiated Three.js objects. -
- -

[method:null setCrossOrigin]( [page:String value] )

-
- [page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS. -
- -

[method:null addGeometryHandler]( [page:String typeID], [page:Function loaderClass] )

-
- [page:String typeID] — The type to handle.
- [page:Function loaderClass] — The handler class.
-
-
- Add an handler for a specific geometry type. -
- -

[method:null addHierarchyHandler]( [page:String typeID], [page:Function loaderClass] )

-
- [page:String typeID] — The type to handle.
- [page:Function loaderClass] — The handler class.
-
-
- Add an handler for a specific object type. -
- - -

Example

- - - // instantiate a loader - var loader = new THREE.SceneLoader(); - - // Handle STL geometries - loader.addGeometryHandler( "stl", THREE.STLLoader ); - - // Handle OBJ objects - loader.addHierarchyHandler( "obj", THREE.OBJLoader ); - - // load a JSON resource - loader.load( - // resource URL - 'scenes/test_scene.js', - // Function when resource is loaded - function ( result ) { - scene.add( result.scene ); - }, - // Function called when download progresses - function ( xhr ) { - console.log( (xhr.loaded / xhr.total * 100) + '% loaded' ); - }, - // Function called when download errors - function ( xhr ) { - console.log( 'An error happened' ); - } - ); - - - [example:webgl_loader_scene] - - -

Source

- - [link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/SceneLoader.js examples/js/loaders/SceneLoader.js] - - diff --git a/docs/api/materials/MeshLambertMaterial.html b/docs/api/materials/MeshLambertMaterial.html index 4028b0ea7d04b7..483dced39f253b 100644 --- a/docs/api/materials/MeshLambertMaterial.html +++ b/docs/api/materials/MeshLambertMaterial.html @@ -29,7 +29,7 @@

[name]([page:Object parameters])

specularMap — Set specular map. Default is null.
alphaMap — Set alpha map. Default is null.
envMap — Set env map. Default is null.
- fog — Define whether the material color is affected by global fog settings. Default is false. + fog — Define whether the material color is affected by global fog settings. Default is false.
shading — How the triangles of a curved surface are rendered. Default is [page:Materials THREE.SmoothShading].
wireframe — Render geometry as wireframe. Default is false (i.e. render as smooth shaded).
wireframeLinewidth — Controls wireframe thickness. Default is 1.
@@ -49,11 +49,6 @@

[property:Color color]

Diffuse color of the material. Default is white.
-

[property:Color ambient]

-
- Ambient color of the material, multiplied by the color of the [page:AmbientLight]. Default is white.
-
-

[property:Color emissive]

Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.
diff --git a/docs/api/materials/MeshNormalMaterial.html b/docs/api/materials/MeshNormalMaterial.html index 37ca144e1b2e17..80b32009d5fad7 100644 --- a/docs/api/materials/MeshNormalMaterial.html +++ b/docs/api/materials/MeshNormalMaterial.html @@ -12,7 +12,7 @@

[name]

A material that maps the normal vectors to RGB colors.
- + @@ -21,10 +21,9 @@

Constructor

[name]([page:Object parameters])

- parameters is an object with one or more properties defining the material's appearance. + parameters is an object with one or more properties defining the material's appearance.
- shading -- How the triangles of a curved surface are rendered. Default is [page:Materials THREE.FlatShading].
wireframe -- Render geometry as wireframe. Default is false (i.e. render as smooth shaded).
wireframeLinewidth -- Controls wireframe thickness. Default is 1.
morphTargets -- Define whether the material uses morphTargets. Default is false.
@@ -34,25 +33,19 @@

[name]([page:Object parameters])

Properties

-

[property:number shading]

+

[property:boolean wireframe]

- How the triangles of a curved surface are rendered: as a smooth surface, as flat separate facets, or no shading at all.

- Options are [page:Materials THREE.SmoothShading], [page:Materials THREE.FlatShading](default) + Render geometry as wireframe. Default is false (i.e. render as smooth shaded).
-

[property:boolean wireframe]

-
- Render geometry as wireframe. Default is false (i.e. render as smooth shaded). -
-

[property:number wireframeLinewidth]

Controls wireframe thickness. Default is 1.

Due to limitations in the ANGLE layer, on Windows platforms linewidth will always be 1 regardless of the set value. -
+

[property:boolean morphTargets]

-
Define whether the material uses morphTargets. Default is false.
+
Define whether the material uses morphTargets. Default is false.

Methods

diff --git a/docs/api/materials/MeshPhongMaterial.html b/docs/api/materials/MeshPhongMaterial.html index 70179ecec63a13..2d84126decc497 100644 --- a/docs/api/materials/MeshPhongMaterial.html +++ b/docs/api/materials/MeshPhongMaterial.html @@ -41,7 +41,7 @@

[name]([page:Object parameters])

Example:
- materials.push( new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } ) ); + materials.push( new THREE.MeshPhongMaterial( { color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } ) );
@@ -54,11 +54,6 @@

[property:Color color]

Diffuse color of the material. Default is white.
-

[property:Color ambient]

-
- Ambient color of the material, multiplied by the color of the [page:AmbientLight]. Default is white.
-
-

[property:Color emissive]

Emissive (light) color of the material, essentially a solid color unaffected by other lighting. Default is black.
@@ -70,7 +65,7 @@

[property:Color specular]

[property:Float shininess]

-
How shiny the specular highlight is; a higher value gives a sharper highlight. Default is *30*.
+
How shiny the specular highlight is; a higher value gives a sharper highlight. Default is *30*. It should not be set to 0.

[property:boolean metal]

diff --git a/docs/api/materials/SpriteMaterial.html b/docs/api/materials/SpriteMaterial.html index 2502628285d9f8..1a47a0ffaf1e74 100644 --- a/docs/api/materials/SpriteMaterial.html +++ b/docs/api/materials/SpriteMaterial.html @@ -24,7 +24,7 @@

[name]( [page:Object parameters] )

color - color of the sprite
map - the texture map
- rotation - the rotation of the sprite + rotation - the rotation of the sprite
fog - whether or not to use the scene fog
diff --git a/docs/api/math/Color.html b/docs/api/math/Color.html index 68a785b313273f..b08ae1d05d2753 100644 --- a/docs/api/math/Color.html +++ b/docs/api/math/Color.html @@ -176,6 +176,14 @@

[method:Color lerp]( [page:Color color], alpha ) [page:Color this]

Linear interpolation of this colors rgb values and the rgb values of the first argument. The alpha argument can be thought of as the percent between the two colors, where 0 is this color and 1 is the first argument.
+

[method:Array toArray]( [page:Array array] )

+
+ array -- Optional array to store the color. +
+
+ Returns an array [r,g,b] +
+

[method:Color equals]( [page:Color c] ) [page:Color this]

Compares this color and c and returns true if they are the same, false otherwise. diff --git a/docs/api/math/Euler.html b/docs/api/math/Euler.html index 4b0ea4232ee2b1..9871338f5f1d46 100644 --- a/docs/api/math/Euler.html +++ b/docs/api/math/Euler.html @@ -1,141 +1,144 @@ - - - - - - - -

[name]

- -
Euler Angles.

- - Euler angles describe a rotation transformation by rotating an object on its various axes in specified amounts per axis, and a specified axis order. - (More information on Wikipedia)
- -

Example

- - var a = new THREE.Euler( 0, 1, 1.57, 'XYZ' ); - var b = new THREE.Vector3( 1, 0, 1 ); - b.applyEuler(a); - - - -

Constructor

- - -

[name]( [page:Float x], [page:Float y], [page:Float z], [page:String order] )

-
- x -- [page:Float] the angle of the x axis in radians
- y -- [page:Float] the angle of the y axis in radians
- z -- [page:Float] the angle of the z axis in radians
- order -- [page:String] A string representing the order that the rotations are applied, defaults to 'XYZ' (must be upper case). -
-
- A euler angle for transforming -
- - -

Properties

- -

[property:Float x]

- -

[property:Float y]

- -

[property:Float z]

- -

[property:String order]

- - - -

Methods

- -

[method:Euler set]( [page:Float x], [page:Float y], [page:Float z], [page:String order] ) [page:Euler this]

-
- x -- [page:Float] Angle in x axis in radians
- y -- [page:Float] Angle in y axis in radians
- z -- [page:Float] Angle in z axis in radians
- order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case) -
-
- Sets the angles of this euler transform. -
- -

[method:Euler copy]( [page:Euler euler] ) [page:Euler this]

-
- Copies value of *euler* to this euler. -
- -

[method:Euler setFromRotationMatrix]( [page:Matrix4 m], [page:String order] ) [page:Euler this]

-
- m -- [page:Matrix4] assumes upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled)
- order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case) -
-
- Sets the angles of this euler transform from a pure rotation matrix based on the orientation specified by order. -
- -

[method:Euler setFromQuaternion]( [page:Quaternion q], [page:String order] ) [page:Euler this]

-
- q -- [page:Quaternion] quaternion must be normalized
- order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case) -
-
- Sets the angles of this euler transform from a normalized quaternion based on the orientation specified by order. -
- -

[method:Euler reorder]( [page:String newOrder] ) [page:Euler this]

-
- Resets the euler angle with a new order by creating a quaternion from this euler angle and then setting this euler angle with the quaternion and the new order.
- WARNING: this discards revolution information. -
- -

[method:Euler setFromVector3]([page:Vector3 vector], [page:String order]) [page:Euler this]

-
- vector -- [page:Vector3]. - order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case) -
-
- Optionally Vector3 to the XYZ parameters of Euler, and order to the Euler's order property. -
- -

[method:Vector3 toVector3]()

-
- Returns the Euler's XYZ properties as a Vector3. -
- -

[method:Euler fromArray]([page:Array array]) [page:Euler this]

-
- array -- [page:Array] of length 3 or 4. array[3] is an optional order argument. -
-
- Assigns this euler's x angle to array[0].
- Assigns this euler's y angle to array[1].
- Assigns this euler's z angle to array[2].
- Optionally assigns this euler's order to array[3]. -
- -

[method:Array toArray]()

-
- Returns an array [x, y, z, order]. -
- -

[method:Boolean equals]( [page:Euler euler] )

-
- Checks for strict equality of this euler and *euler*. -
- -

[method:Euler clone]()

-
- Returns a new euler created from this euler. -
- - - - -

Source

- - [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] - + + + + + + + +

[name]

+ +
Euler Angles.

+ + Euler angles describe a rotation transformation by rotating an object on its various axes in specified amounts per axis, and a specified axis order. + (More information on Wikipedia)
+ +

Example

+ + var a = new THREE.Euler( 0, 1, 1.57, 'XYZ' ); + var b = new THREE.Vector3( 1, 0, 1 ); + b.applyEuler(a); + + + +

Constructor

+ + +

[name]( [page:Float x], [page:Float y], [page:Float z], [page:String order] )

+
+ x -- [page:Float] the angle of the x axis in radians
+ y -- [page:Float] the angle of the y axis in radians
+ z -- [page:Float] the angle of the z axis in radians
+ order -- [page:String] A string representing the order that the rotations are applied, defaults to 'XYZ' (must be upper case). +
+
+ A euler angle for transforming +
+ + +

Properties

+ +

[property:Float x]

+ +

[property:Float y]

+ +

[property:Float z]

+ +

[property:String order]

+ + + +

Methods

+ +

[method:Euler set]( [page:Float x], [page:Float y], [page:Float z], [page:String order] ) [page:Euler this]

+
+ x -- [page:Float] Angle in x axis in radians
+ y -- [page:Float] Angle in y axis in radians
+ z -- [page:Float] Angle in z axis in radians
+ order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case) +
+
+ Sets the angles of this euler transform. +
+ +

[method:Euler copy]( [page:Euler euler] ) [page:Euler this]

+
+ Copies value of *euler* to this euler. +
+ +

[method:Euler setFromRotationMatrix]( [page:Matrix4 m], [page:String order] ) [page:Euler this]

+
+ m -- [page:Matrix4] assumes upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled)
+ order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case) +
+
+ Sets the angles of this euler transform from a pure rotation matrix based on the orientation specified by order. +
+ +

[method:Euler setFromQuaternion]( [page:Quaternion q], [page:String order] ) [page:Euler this]

+
+ q -- [page:Quaternion] quaternion must be normalized
+ order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case) +
+
+ Sets the angles of this euler transform from a normalized quaternion based on the orientation specified by order. +
+ +

[method:Euler reorder]( [page:String newOrder] ) [page:Euler this]

+
+ Resets the euler angle with a new order by creating a quaternion from this euler angle and then setting this euler angle with the quaternion and the new order.
+ WARNING: this discards revolution information. +
+ +

[method:Euler setFromVector3]([page:Vector3 vector], [page:String order]) [page:Euler this]

+
+ vector -- [page:Vector3]. + order -- [page:string] Order of axes, defaults to 'XYZ' (must be upper case) +
+
+ Optionally Vector3 to the XYZ parameters of Euler, and order to the Euler's order property. +
+ +

[method:Vector3 toVector3]()

+
+ Returns the Euler's XYZ properties as a Vector3. +
+ +

[method:Euler fromArray]([page:Array array]) [page:Euler this]

+
+ array -- [page:Array] of length 3 or 4. array[3] is an optional order argument. +
+
+ Assigns this euler's x angle to array[0].
+ Assigns this euler's y angle to array[1].
+ Assigns this euler's z angle to array[2].
+ Optionally assigns this euler's order to array[3]. +
+ +

[method:Array toArray]( [page:Array array] )

+
+ array -- Optional array to store the euler. +
+
+ Returns an array [x, y, z, order] +
+ +

[method:Boolean equals]( [page:Euler euler] )

+
+ Checks for strict equality of this euler and *euler*. +
+ +

[method:Euler clone]()

+
+ Returns a new euler created from this euler. +
+ + + + +

Source

+ + [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js] + diff --git a/docs/api/math/Matrix4.html b/docs/api/math/Matrix4.html index 9b494e103ecf82..72ee6b3d08a307 100644 --- a/docs/api/math/Matrix4.html +++ b/docs/api/math/Matrix4.html @@ -165,8 +165,7 @@

[method:Matrix4 compose]( [page:Vector3 translation], [page:Quaternion quate

[method:Array decompose]( [page:Vector3 translation], [page:Quaternion quaternion], [page:Vector3 scale] )

- Decomposes this matrix into the *translation*, *quaternion* and *scale* components.
- If parameters are not passed, new instances will be created. + Decomposes this matrix into the *translation*, *quaternion* and *scale* components.

[method:Matrix4 makeTranslation]( [page:Float x], [page:Float y], [page:Float z] ) [page:Matrix4 this]

diff --git a/docs/api/math/Quaternion.html b/docs/api/math/Quaternion.html index 139194281fa13e..25735bfbe00454 100644 --- a/docs/api/math/Quaternion.html +++ b/docs/api/math/Quaternion.html @@ -131,15 +131,18 @@

[method:Quaternion slerp]( [page:Quaternion qa], [page:Quaternion qb], [page

[method:Quaternion slerp]([page:Quaternion qb], [page:float t])

qb -- Target quaternion rotation.
- t -- Normalized [0..1] interpolation factor. + t -- Normalized [0..1] interpolation factor.
Handles the spherical linear interpolation between this quaternion's configuration - and that of *qb*. *t* represents how close to the current (0) or target (1) rotation the - result should be. + and that of *qb*. *t* represents how close to the current (0) or target (1) rotation the + result should be.
-

.toArray() [page: Array]

+

[method:Array toArray]( [page:Array array] )

+
+ array -- Array to store the quaternion. +
Returns the numerical elements of this quaternion in an array of format (x, y, z, w).
@@ -155,7 +158,7 @@

[method:Boolean equals]([page:Quaternion v])

[method:Float lengthSq]()

- Calculates the squared length of the quaternion. + Calculates the squared length of the quaternion.

[method:Quaternion fromArray]([page:Array array])

diff --git a/docs/api/math/Vector2.html b/docs/api/math/Vector2.html index c09dec2c3049bf..f1bdc572cbf509 100644 --- a/docs/api/math/Vector2.html +++ b/docs/api/math/Vector2.html @@ -226,7 +226,10 @@

[method:Vector2 fromArray]([page:Array array]) [page:Vector2 this]

Sets this vector's x value to be array[0] and y value to be array[1].
-

[method:Array toArray]()

+

[method:Array toArray]( [page:Array array] )

+
+ array -- Optional array to store the vector. +
Returns an array [x, y].
diff --git a/docs/api/math/Vector3.html b/docs/api/math/Vector3.html index 0f5738b3d886a3..bc2d47a0770851 100644 --- a/docs/api/math/Vector3.html +++ b/docs/api/math/Vector3.html @@ -401,7 +401,10 @@

[method:Vector3 applyProjection]([page:Matrix4 m]) [page:Vector3 this]

Multiplies this vector and m, and divides by perspective. -

[method:Array toArray]()

+

[method:Array toArray]( [page:Array array] )

+
+ array -- Optional array to store the vector. +
Assigns this vector's x value to array[0].
Assigns this vector's y value to array[1].
diff --git a/docs/api/math/Vector4.html b/docs/api/math/Vector4.html index 5d0733cf82bbaf..a874c8964a2c70 100644 --- a/docs/api/math/Vector4.html +++ b/docs/api/math/Vector4.html @@ -186,7 +186,7 @@

[method:Vector4 max]([page:Vector4 v]) [page:Vector4 this]

v -- [page:Vector4]
- If this vector's x, y, z, or w value is greater than vector v's x, y, z, or w value, that value is replaced by the corresponding vector v value. + If this vector's x, y, z, or w value is greater than vector v's x, y, z, or w value, that value is replaced by the corresponding vector v value.

[method:Vector4 addScalar]([page:Float s]) [page:Vector4 this]

@@ -204,7 +204,7 @@

[method:Boolean equals]([page:Vector4 v])

Checks to see if this vector matches vector v.
- +

[method:Vector4 setAxisAngleFromRotationMatrix]([page:Matrix4 m]) [page:Vector4 this]

m -- [page:Matrix4] @@ -236,7 +236,7 @@

[method:Float getComponent]([page:Integer index])

Index 1: y
Index 2: z
Index 3: w
- +

[method:null setComponent]([page:Integer index], [page:Float value])

@@ -246,13 +246,13 @@

[method:null setComponent]([page:Integer index], [page:Float value])

Sets the value of the vector component x, y, or z by an index.

- + Index 0: x
Index 1: y
Index 2: z
Index 3: w
- +

[method:Vector4 fromArray]([page:Array array]) [page:Vector4 this]

array -- [page:Array] An array formatted [x, y, z, w] @@ -261,7 +261,10 @@

[method:Vector4 fromArray]([page:Array array]) [page:Vector4 this]

Sets the vector's components based on an array formatted like [x, y, z, w]
-

[method:Array toArray]()

+

[method:Array toArray]( [page:Array array] )

+
+ array -- Optional array to store the vector. +
Returns an array in the format [x, y, z, w]
diff --git a/docs/api/renderers/WebGLRenderTarget.html b/docs/api/renderers/WebGLRenderTarget.html index af53625acae21e..8f6403412af5db 100644 --- a/docs/api/renderers/WebGLRenderTarget.html +++ b/docs/api/renderers/WebGLRenderTarget.html @@ -69,7 +69,7 @@

[property:number format]

[property:number type]

- The default is THREE.UnsignedByteType. Other valid types (as WebGL allows) are THREE.ByteType, THREE.ShortType, THREE.UnsignedShortType, THREE.IntType, THREE.UnsignedIntType, THREE.FloatType, THREE.UnsignedShort4444Type, THREE.UnsignedShort5551Type, and THREE.UnsignedShort565Type. + The default is THREE.UnsignedByteType. Other valid types (as WebGL allows) are THREE.ByteType, THREE.ShortType, THREE.UnsignedShortType, THREE.IntType, THREE.UnsignedIntType, THREE.HalfFloatType, THREE.FloatType, THREE.UnsignedShort4444Type, THREE.UnsignedShort5551Type, and THREE.UnsignedShort565Type.

[property:boolean depthBuffer]

diff --git a/docs/index.html b/docs/index.html index 7ce1d59f9c0415..5b2f85dee1bb19 100644 --- a/docs/index.html +++ b/docs/index.html @@ -269,11 +269,11 @@

three.js / docs

var li = document.createElement( 'li' ); var a = document.createElement( 'a' ); a.setAttribute( 'href', '#' ); - ( function( s, c, p ) { + ( function( s, c, p ) { a.addEventListener( 'click', function( e ) { goTo( s, c, p ); e.preventDefault(); - } ) + } ) } )( section, category, page[ 0 ] ) a.textContent = page[ 0 ]; li.appendChild( a ); @@ -370,7 +370,7 @@

three.js / docs

// Resolve links of the form 'Class.member' if(section.indexOf(MEMBER_DELIMITER) !== -1) { parts = section.split(MEMBER_DELIMITER) - section = parts[0]; + section = parts[0]; member = parts[1]; } @@ -379,7 +379,7 @@

three.js / docs

section = location.section; category = location.category; name = location.name; - } + } var title = 'three.js - documentation - ' + section + ' - ' + name; var url = encodeUrl(section) + DELIMITER + encodeUrl( category ) + DELIMITER + encodeUrl(name) + (!!member ? MEMBER_DELIMITER + encodeUrl(member) : ''); @@ -405,6 +405,18 @@

three.js / docs

if ( window.location.hash.length > 0 ) goToHash(); + console.log([ + ' __ __', + ' __/ __\\ / __\\__ ____ _____ _____', + '/ __/ /\\/ / /___\\/ ____\\/ _____\\/ _____\\', + '\\/_ __/ / _ / / __/ / __ / / __ /_ __ _____', + '/ / / / / / / / / / / / ___/ / ___/\\ _\\/ __\\/ _____\\', + '\\/__/ \\/__/\\/__/\\/__/ \\/_____/\\/_____/\\/__/ / / / ___/', + ' / __/ / \\__ \\', + ' \\/____/\\/_____/' + ].join('\n')); + + diff --git a/docs/list.js b/docs/list.js index 0c5258ac8a49e7..7a71ca4fe447e7 100644 --- a/docs/list.js +++ b/docs/list.js @@ -63,7 +63,6 @@ var list = { [ "ObjectLoader", "api/loaders/ObjectLoader" ], [ "PDBLoader", "api/loaders/PDBLoader" ], [ "SVGLoader", "api/loaders/SVGLoader" ], - [ "SceneLoader", "api/loaders/SceneLoader" ], [ "TextureLoader", "api/loaders/TextureLoader" ], [ "TGALoader", "api/loaders/TGALoader" ], [ "XHRLoader", "api/loaders/XHRLoader" ] diff --git a/docs/scenes/js/material.js b/docs/scenes/js/material.js index 98ffbcc16c02d6..6f3bf3fbbdad61 100644 --- a/docs/scenes/js/material.js +++ b/docs/scenes/js/material.js @@ -393,7 +393,6 @@ function guiMeshLambertMaterial ( gui, mesh, material, geometry ) { var data = { color : material.color.getHex(), - ambient : material.ambient.getHex(), emissive : material.emissive.getHex(), envMaps : envMapKeys, map : textureMapKeys, @@ -407,7 +406,6 @@ function guiMeshLambertMaterial ( gui, mesh, material, geometry ) { var folder = gui.addFolder('THREE.MeshLambertMaterial'); folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) ); - folder.addColor( data, 'ambient' ).onChange( handleColorChange( material.ambient ) ); folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) ); folder.add( material, 'shading', constants.shading ).onChange( needsUpdate( material, geometry ) ); @@ -433,7 +431,6 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) { var data = { color : material.color.getHex(), - ambient : material.ambient.getHex(), emissive : material.emissive.getHex(), specular : material.specular.getHex(), envMaps : envMapKeys, @@ -446,11 +443,10 @@ function guiMeshPhongMaterial ( gui, mesh, material, geometry ) { var folder = gui.addFolder('THREE.MeshPhongMaterial'); folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) ); - folder.addColor( data, 'ambient' ).onChange( handleColorChange( material.ambient ) ); folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) ); folder.addColor( data, 'specular' ).onChange( handleColorChange( material.specular ) ); - folder.add( material, 'shininess', 0, 100); + folder.add( material, 'shininess', 1, 100); folder.add( material, 'shading', constants.shading).onChange( needsUpdate( material, geometry ) ); folder.add( material, 'wireframe' ); folder.add( material, 'wireframeLinewidth', 0, 10 ); diff --git a/editor/css/dark.css b/editor/css/dark.css index 70a22c3e18c596..0dc1940ec1e456 100644 --- a/editor/css/dark.css +++ b/editor/css/dark.css @@ -1,17 +1,21 @@ -.FancySelect { +.Outliner { + color: #868686; background: #222; padding: 0; + width: 100%; + height: 140px; + font-size: 12px; cursor: default; overflow: auto; outline: none; } - .FancySelect .option { + .Outliner .option { padding: 4px; white-space: nowrap; } - .FancySelect .option.active { + .Outliner .option.active { background-color: #153C5E; } @@ -159,13 +163,6 @@ input.Number { border-top: 1px solid #333; } - #sidebar #outliner { - width: 100%; - height: 140px; - color: #868686; - font-size: 12px; - } - #sidebar .Panel.Material canvas { border: solid 1px #5A5A5A; diff --git a/editor/css/light.css b/editor/css/light.css index 998db6b32148b7..f2672285c5f596 100644 --- a/editor/css/light.css +++ b/editor/css/light.css @@ -1,18 +1,22 @@ -.FancySelect { +.Outliner { + color: #444; background: #fff; padding: 0; + width: 100%; + height: 140px; + font-size: 12px; cursor: default; overflow: auto; outline: none; } - .FancySelect .option { + .Outliner .option { padding: 4px; color: #666; white-space: nowrap; } - .FancySelect .option.active { + .Outliner .option.active { background-color: #f8f8f8; } @@ -152,13 +156,6 @@ input.Number { border-top: 1px solid #ccc; } - #sidebar #outliner { - width: 100%; - height: 140px; - color: #444; - font-size: 12px; - } - #toolbar { position: absolute; left: 0px; diff --git a/editor/css/main.css b/editor/css/main.css index 59d7904c66c9ed..8e4319c37717d1 100644 --- a/editor/css/main.css +++ b/editor/css/main.css @@ -67,6 +67,8 @@ textarea, input { outline: none; } /* osx */ display: none; } +/* CodeMirror */ + .CodeMirror { position: absolute !important; @@ -76,6 +78,20 @@ textarea, input { outline: none; } /* osx */ } + .CodeMirror .errorLine { + + background: rgba(255,0,0,0.25); + + } + + .CodeMirror .esprima-error { + + color: #f00; + text-align: right; + padding: 0px 20px; + + } + /* scene types */ .type { diff --git a/editor/examples/arkanoid.app.json b/editor/examples/arkanoid.app.json old mode 100644 new mode 100755 index 84d6e41f1091d5..0273a34e73a9e2 --- a/editor/examples/arkanoid.app.json +++ b/editor/examples/arkanoid.app.json @@ -6,7 +6,7 @@ "generator": "ObjectExporter" }, "object": { - "uuid": "A32F9E56-4DDC-442E-8A0D-F23B9E93EEA9", + "uuid": "8EFB9C06-6312-4975-B04A-C9E4549BE348", "type": "PerspectiveCamera", "name": "Camera", "fov": 50, @@ -107,7 +107,7 @@ "name": "Ground", "geometry": "8F05A1F2-3877-478B-8DFC-F572AC61AB3A", "material": "2F69AF3A-DDF5-4BBA-87B5-80159F90DDBF", - "matrix": [1,0,0,0,0,0.0007962886593304574,-0.9999997019767761,0,0,0.9999997019767761,0.0007962886593304574,0,0,0,0,1] + "matrix": [1,0,0,0,0,0.000796250649727881,-0.9999997019767761,0,0,0.9999997019767761,0.000796250649727881,0,0,0,0,1] }, { "uuid": "6EE2E764-43E0-48E0-85F2-E0C8823C20DC", @@ -148,6 +148,7 @@ "color": 16777215, "intensity": 1, "distance": 0, + "decay": 1, "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-116.54356384277344,69.48957061767578,-206.8248291015625,1] }] } @@ -161,7 +162,7 @@ "31517222-A9A7-4EAF-B5F6-60751C0BABA3": [ { "name": "Game Logic", - "source": "var ball = this.getObjectByName( 'Ball' );\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = - 0.5;\ndirection.normalize();\n\nvar speed = new THREE.Vector3();\n\n//\n\nvar group = new THREE.Group();\nthis.add( group );\n\nvar paddle = this.getObjectByName( 'Paddle' );\ngroup.add( paddle );\n\nvar brick = this.getObjectByName( 'Brick' );\n\nfor ( var j = 0; j < 8; j ++ ) {\n\n\tvar material = new THREE.MeshPhongMaterial( { color: Math.random() * 0xffffff } );\n\n\tfor ( var i = 0; i < 12; i ++ ) {\n\t\t\n\t\tvar object = brick.clone();\n\t\tobject.material = material;\n\t\tobject.position.x = i * 22 - 120;\n\t\tobject.position.z = j * 14 - 120;\n\t\tgroup.add( object );\n\t\t\n\t}\n\t\n}\n\nbrick.visible = false;\n\n//\n\nvar raycaster = new THREE.Raycaster();\n\nfunction update( event ) {\n\t\n\tif ( ball.position.x < - 150 || ball.position.x > 150 ) direction.x = - direction.x;\n\tif ( ball.position.z < - 200 || ball.position.z > 200 ) direction.z = - direction.z;\n\n\tball.position.add( speed.copy( direction ).multiplyScalar( 4 ) );\n\t\n\traycaster.set( ball.position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( group.children );\n\t\n\tif ( intersections.length > 0 ) {\n\t\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 5 ) {\n\t\t\t\n\t\t\tif ( intersection.object !== paddle ) {\n\n\t\t\t\tgroup.remove( intersection.object );\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n}" + "source": "var ball = this.getObjectByName( 'Ball' );\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = - 0.5;\ndirection.normalize();\n\nvar speed = new THREE.Vector3();\n\n//\n\nvar group = new THREE.Group();\nthis.add( group );\n\nvar paddle = this.getObjectByName( 'Paddle' );\ngroup.add( paddle );\n\nvar brick = this.getObjectByName( 'Brick' );\n\nfor ( var j = 0; j < 8; j ++ ) {\n\n\tvar material = new THREE.MeshPhongMaterial( { color: Math.random() * 0xffffff } );\n\n\tfor ( var i = 0; i < 12; i ++ ) {\n\t\t\n\t\tvar object = brick.clone();\n\t\tobject.material = material;\n\t\tobject.position.x = i * 22 - 120;\n\t\tobject.position.z = j * 14 - 120;\n\t\tgroup.add( object );\n\t\t\n\t}\n\t\n}\n\nbrick.visible = false;\n\n//\n\nvar raycaster = new THREE.Raycaster();\n\nfunction update( event ) {\n\t\n\tif ( ball.position.x < - 150 || ball.position.x > 150 ) direction.x = - direction.x;\n\tif ( ball.position.z < - 200 || ball.position.z > 200 ) direction.z = - direction.z;\n\n\tball.position.x = Math.max( - 150, Math.min( 150, ball.position.x ) );\n\tball.position.z = Math.max( - 200, Math.min( 200, ball.position.z ) );\n\t\n\tball.position.add( speed.copy( direction ).multiplyScalar( event.delta / 4 ) );\n\t\n\traycaster.set( ball.position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( group.children );\n\t\n\tif ( intersections.length > 0 ) {\n\t\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 5 ) {\n\t\t\t\n\t\t\tif ( intersection.object !== paddle ) {\n\n\t\t\t\tgroup.remove( intersection.object );\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n}" }] } -} +} \ No newline at end of file diff --git a/editor/examples/camera.app.json b/editor/examples/camera.app.json old mode 100644 new mode 100755 index 1ff8d5252c4338..e4c7905d84db2c --- a/editor/examples/camera.app.json +++ b/editor/examples/camera.app.json @@ -6,14 +6,14 @@ "generator": "ObjectExporter" }, "object": { - "uuid": "F0D8434F-4603-415B-8024-792FE97B9600", + "uuid": "C7FB195B-270E-47B4-95C9-1754652A9D11", "type": "PerspectiveCamera", "name": "Camera", "fov": 50, "aspect": 1.2252042007001167, "near": 0.1, "far": 100000, - "matrix": [0.9700406789779663,-5.500052080442686e-10,-0.24294254183769226,0,-0.04822639003396034,0.9800989627838135,-0.19256223738193512,0,0.23810774087905884,0.19850945472717285,0.950735867023468,0,159.0158233642578,132.5708465576172,634.9312744140625,1] + "matrix": [0.9700406789779663,-2.851828329042405e-9,-0.24294254183769226,0,-0.04822639003396034,0.9800989627838135,-0.1925622522830963,0,0.23810774087905884,0.19850945472717285,0.950735867023468,0,154.7735595703125,129.03408813476562,617.992431640625,1] } }, "scene": { @@ -23,6 +23,14 @@ "generator": "ObjectExporter" }, "geometries": [ + { + "uuid": "51BB3E54-D2DF-4576-9953-FB8E940588B5", + "type": "PlaneGeometry", + "width": 1000, + "height": 1000, + "widthSegments": 1, + "heightSegments": 1 + }, { "uuid": "D8E200D3-27BC-49F8-A5C5-7384206E70FE", "type": "BoxGeometry", @@ -43,14 +51,6 @@ "heightSegments": 1, "openEnded": false }, - { - "uuid": "51BB3E54-D2DF-4576-9953-FB8E940588B5", - "type": "PlaneGeometry", - "width": 1000, - "height": 1000, - "widthSegments": 1, - "heightSegments": 1 - }, { "uuid": "4DECFAB5-6FD1-4D84-9A29-565807B074EA", "type": "IcosahedronGeometry", @@ -59,25 +59,25 @@ }], "materials": [ { - "uuid": "B5943856-E404-45D9-A427-4774202C2CD0", + "uuid": "4AE8130E-B6A8-47BC-ACCF-060973C74044", "type": "MeshPhongMaterial", - "color": 37119, + "color": 16777215, "emissive": 0, "specular": 1118481, "shininess": 30 }, { - "uuid": "3F872310-2067-4BE4-9250-5B3F4E43797E", + "uuid": "B5943856-E404-45D9-A427-4774202C2CD0", "type": "MeshPhongMaterial", - "color": 15859456, + "color": 37119, "emissive": 0, "specular": 1118481, "shininess": 30 }, { - "uuid": "4AE8130E-B6A8-47BC-ACCF-060973C74044", + "uuid": "3F872310-2067-4BE4-9250-5B3F4E43797E", "type": "MeshPhongMaterial", - "color": 16777215, + "color": 15859456, "emissive": 0, "specular": 1118481, "shininess": 30 @@ -97,19 +97,34 @@ "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1], "children": [ { - "uuid": "60B69C58-4201-43FD-815E-AD2EDFBBD0CE", - "type": "PerspectiveCamera", - "name": "PerspectiveCamera 1", - "fov": 50, - "aspect": 1, - "near": 100, - "far": 10000, - "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,100,400,1] + "uuid": "B7CBBC6F-EC26-49B5-8D0D-67D9C535924B", + "type": "Group", + "name": "Dummy", + "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,100,400,1], + "children": [ + { + "uuid": "60B69C58-4201-43FD-815E-AD2EDFBBD0CE", + "type": "PerspectiveCamera", + "name": "PerspectiveCamera", + "fov": 50, + "aspect": 1, + "near": 100, + "far": 10000, + "matrix": [-1,0,-1.2246468525851679e-16,0,0,1,0,0,1.2246468525851679e-16,0,-1,0,0,0,0,1] + }] + }, + { + "uuid": "A460C230-DC88-4A8F-A3FB-AA0FE735F3ED", + "type": "Mesh", + "name": "Plane", + "geometry": "51BB3E54-D2DF-4576-9953-FB8E940588B5", + "material": "4AE8130E-B6A8-47BC-ACCF-060973C74044", + "matrix": [1,0,0,0,0,0.040785226970911026,-0.9991679191589355,0,0,0.9991679191589355,0.040785226970911026,0,0,-50,0,1] }, { "uuid": "26DAAD69-725D-43B7-AF9D-990A99DEF8C5", "type": "Mesh", - "name": "Box 1", + "name": "Box", "geometry": "D8E200D3-27BC-49F8-A5C5-7384206E70FE", "material": "B5943856-E404-45D9-A427-4774202C2CD0", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] @@ -117,27 +132,18 @@ { "uuid": "AAAFF2D6-4725-4AFC-A9FE-26419B11011F", "type": "Mesh", - "name": "Cylinder 3", + "name": "Cylinder", "geometry": "25BA32DB-8B02-4ABA-A77C-69868C464A1A", "material": "3F872310-2067-4BE4-9250-5B3F4E43797E", "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-130,-15,0,1] }, { - "uuid": "A460C230-DC88-4A8F-A3FB-AA0FE735F3ED", + "uuid": "B855E267-A266-4098-ACD6-6A1FDE7B88BA", "type": "Mesh", - "name": "Plane 4", - "geometry": "51BB3E54-D2DF-4576-9953-FB8E940588B5", - "material": "4AE8130E-B6A8-47BC-ACCF-060973C74044", - "matrix": [1,0,0,0,0,0.040785059332847595,-0.9991679191589355,0,0,0.9991679191589355,0.040785059332847595,0,0,-50,0,1] - }, - { - "uuid": "3412781E-27CC-43C3-A5DB-54C0C8E42ED6", - "type": "PointLight", - "name": "PointLight 2", - "color": 12773063, - "intensity": 1, - "distance": 0, - "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,88.12999725341797,8.3100004196167,125.44999694824219,1] + "name": "Icosahedron", + "geometry": "4DECFAB5-6FD1-4D84-9A29-565807B074EA", + "material": "E1826901-7922-4584-A25D-6D487E2C9BBD", + "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,130,-10,0,1] }, { "uuid": "E2939A7B-5E40-438A-8C1B-32126FBC6892", @@ -146,23 +152,31 @@ "color": 9474221, "intensity": 0.75, "distance": 0, + "decay": 1, "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,-93.86000061035156,127.12999725341797,-114.30000305175781,1] }, { - "uuid": "B855E267-A266-4098-ACD6-6A1FDE7B88BA", - "type": "Mesh", - "name": "Icosahedron 1", - "geometry": "4DECFAB5-6FD1-4D84-9A29-565807B074EA", - "material": "E1826901-7922-4584-A25D-6D487E2C9BBD", - "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,130,-10,0,1] + "uuid": "3412781E-27CC-43C3-A5DB-54C0C8E42ED6", + "type": "PointLight", + "name": "PointLight 2", + "color": 12773063, + "intensity": 1, + "distance": 0, + "decay": 1, + "matrix": [1,0,0,0,0,1,0,0,0,0,1,0,88.12999725341797,8.3100004196167,125.44999694824219,1] }] } }, "scripts": { "60B69C58-4201-43FD-815E-AD2EDFBBD0CE": [ { - "name": "Camera Orbit", - "source": "player.setCamera( this );\n\nfunction update( event ) {\n\n\tvar time = event.time * 0.001;\n\n\tthis.position.x = Math.sin( time ) * 400;\n\tthis.position.z = Math.cos( time ) * 400;\n\tthis.lookAt( scene.position );\n\n}" + "name": "Player Camera", + "source": "player.setCamera( this );" + }], + "B7CBBC6F-EC26-49B5-8D0D-67D9C535924B": [ + { + "name": "Orbit", + "source": "function update( event ) {\n\n\tvar time = event.time * 0.001;\n\n\tthis.position.x = Math.sin( time ) * 400;\n\tthis.position.z = Math.cos( time ) * 400;\n\tthis.lookAt( scene.position );\n\n}" }] } -} +} \ No newline at end of file diff --git a/editor/examples/pong.app.json b/editor/examples/pong.app.json old mode 100644 new mode 100755 index 69cd7a762bb027..9b8a983c54e653 --- a/editor/examples/pong.app.json +++ b/editor/examples/pong.app.json @@ -6,7 +6,7 @@ "generator": "ObjectExporter" }, "object": { - "uuid": "E5C76691-3D55-4E26-862E-24BADC21F4D7", + "uuid": "8EFB9C06-6312-4975-B04A-C9E4549BE348", "type": "PerspectiveCamera", "name": "Camera", "fov": 50, @@ -88,7 +88,7 @@ "name": "Ground", "geometry": "77B20ED1-2871-4B14-A652-8F823B2A817E", "material": "7EDF7C08-6325-418A-BBAB-89341C694730", - "matrix": [1,0,0,0,0,0.0007961748051457107,-0.9999997019767761,0,0,0.9999997019767761,0.0007961748051457107,0,0,-10,0,1] + "matrix": [1,0,0,0,0,0.0007960614748299122,-0.9999997019767761,0,0,0.9999997019767761,0.0007960614748299122,0,0,-10,0,1] }, { "uuid": "CE13E58A-4E8B-4F72-9E2E-7DE57C58F989", @@ -128,7 +128,7 @@ "31517222-A9A7-4EAF-B5F6-60751C0BABA3": [ { "name": "Game logic", - "source": "var ball = this.getObjectByName( 'Ball' );\n\nvar position = ball.position;\n\nvar velocity = new THREE.Vector3();\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = Math.random() - 0.5;\ndirection.normalize();\n\nvar pad1 = this.getObjectByName( 'Pad 1' );\nvar pad2 = this.getObjectByName( 'Pad 2' );\n\nvar raycaster = new THREE.Raycaster();\nvar objects = [ pad1, pad2 ];\n\n//\n\nfunction mousemove( event ) {\n\n\tpad1.position.z = ( event.clientX / player.width ) * 300 - 150;\n\tpad2.position.z = - pad1.position.z;\n\n}\n\nfunction update( event ) {\n\n\tif ( position.x < -300 || position.x > 300 ) {\n\t\t\n\t\tdirection.x = - direction.x;\n\t\t\n\t}\n\n\tif ( position.z < -200 || position.z > 200 ) {\n\t\t\n\t\tdirection.z = - direction.z;\n\t\t\n\t}\n\t\n\traycaster.set( position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( objects );\n\t\n\tif ( intersections.length > 0 ) {\n\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 10 ) {\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n\tposition.add( velocity.copy( direction ).multiplyScalar( 8 ) );\n\n}" + "source": "var ball = this.getObjectByName( 'Ball' );\n\nvar position = ball.position;\n\nvar velocity = new THREE.Vector3();\n\nvar direction = new THREE.Vector3();\ndirection.x = Math.random() - 0.5;\ndirection.z = Math.random() - 0.5;\ndirection.normalize();\n\nvar pad1 = this.getObjectByName( 'Pad 1' );\nvar pad2 = this.getObjectByName( 'Pad 2' );\n\nvar raycaster = new THREE.Raycaster();\nvar objects = [ pad1, pad2 ];\n\n//\n\nfunction mousemove( event ) {\n\n\tpad1.position.z = ( event.clientX / player.width ) * 300 - 150;\n\tpad2.position.z = - pad1.position.z;\n\n}\n\nfunction update( event ) {\n\t\n\tif ( position.x < -300 || position.x > 300 ) direction.x = - direction.x;\n\tif ( position.z < -200 || position.z > 200 ) direction.z = - direction.z;\n\t\n\tposition.x = Math.max( - 300, Math.min( 300, position.x ) );\n\tposition.z = Math.max( - 200, Math.min( 200, position.z ) );\n\t\n\traycaster.set( position, direction );\n\t\n\tvar intersections = raycaster.intersectObjects( objects );\n\t\n\tif ( intersections.length > 0 ) {\n\n\t\tvar intersection = intersections[ 0 ];\n\t\t\n\t\tif ( intersection.distance < 10 ) {\n\t\t\t\n\t\t\tdirection.reflect( intersection.face.normal );\n\t\t\t\n\t\t}\n\t\t\n\t}\n\n\tposition.add( velocity.copy( direction ).multiplyScalar( event.delta / 2 ) );\n\n}" }] } -} +} \ No newline at end of file diff --git a/editor/index.html b/editor/index.html index f2ef6ffc17ea66..4ac1c041e8cd8b 100644 --- a/editor/index.html +++ b/editor/index.html @@ -19,7 +19,6 @@ - @@ -30,6 +29,8 @@ + + @@ -40,8 +41,10 @@ + + @@ -50,6 +53,9 @@ + + + @@ -213,7 +219,12 @@ document.addEventListener( 'drop', function ( event ) { event.preventDefault(); - editor.loader.loadFile( event.dataTransfer.files[ 0 ] ); + + if ( event.dataTransfer.files.length > 0 ) { + + editor.loader.loadFile( event.dataTransfer.files[ 0 ] ); + + } }, false ); diff --git a/editor/js/Editor.js b/editor/js/Editor.js index cc1fc8d7381469..34412e6561f3ad 100644 --- a/editor/js/Editor.js +++ b/editor/js/Editor.js @@ -155,7 +155,31 @@ Editor.prototype = { }, - setObjectName: function ( object, name ) { + moveObject: function ( object, parent, before ) { + + if ( parent === undefined ) { + + parent = this.scene; + + } + + parent.add( object ); + + // sort children array + + if ( before !== undefined ) { + + var index = parent.children.indexOf( before ); + parent.children.splice( index, 0, object ); + parent.children.pop(); + + } + + this.signals.sceneGraphChanged.dispatch(); + + }, + + nameObject: function ( object, name ) { object.name = name; this.signals.sceneGraphChanged.dispatch(); @@ -319,22 +343,6 @@ Editor.prototype = { // - parent: function ( object, parent ) { - - if ( parent === undefined ) { - - parent = this.scene; - - } - - parent.add( object ); - - this.signals.sceneGraphChanged.dispatch(); - - }, - - // - select: function ( object ) { if ( this.selected === object ) return; @@ -462,6 +470,9 @@ Editor.prototype = { return { + project: { + vr: this.config.getKey( 'project/vr' ) + }, camera: this.camera.toJSON(), scene: this.scene.toJSON(), scripts: this.scripts diff --git a/editor/js/Menubar.Edit.js b/editor/js/Menubar.Edit.js index 246713c83d0a6c..dbe75877094dcb 100644 --- a/editor/js/Menubar.Edit.js +++ b/editor/js/Menubar.Edit.js @@ -53,38 +53,6 @@ Menubar.Edit = function ( editor ) { } ); options.add( option ); - // - - options.add( new UI.HorizontalRule() ); - - // Flatten - - var option = new UI.Panel(); - option.setClass( 'option' ); - option.setTextContent( 'Flatten' ); - option.onClick( function () { - - var object = editor.selected; - - if ( object.parent === undefined ) return; // avoid flattening the camera or scene - - if ( confirm( 'Flatten ' + object.name + '?' ) === false ) return; - - var geometry = object.geometry; - - geometry.applyMatrix( object.matrix ); - geometry.verticesNeedUpdate = true; - geometry.normalsNeedUpdate = true; - - object.position.set( 0, 0, 0 ); - object.rotation.set( 0, 0, 0 ); - object.scale.set( 1, 1, 1 ); - - editor.signals.objectChanged.dispatch( object ); - - } ); - options.add( option ); - return container; }; diff --git a/editor/js/Menubar.File.js b/editor/js/Menubar.File.js index 2a4efe36e4396a..cef2075803bb6a 100644 --- a/editor/js/Menubar.File.js +++ b/editor/js/Menubar.File.js @@ -89,7 +89,7 @@ Menubar.File = function ( editor ) { output = JSON.stringify( output, null, '\t' ); output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' ); - exportString( output ); + exportString( output, 'geometry.json' ); } ); options.add( option ); @@ -114,7 +114,7 @@ Menubar.File = function ( editor ) { output = JSON.stringify( output, null, '\t' ); output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' ); - exportString( output ); + exportString( output, 'model.json' ); } ); options.add( option ); @@ -130,7 +130,7 @@ Menubar.File = function ( editor ) { output = JSON.stringify( output, null, '\t' ); output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' ); - exportString( output ); + exportString( output, 'scene.json' ); } ); options.add( option ); @@ -153,7 +153,7 @@ Menubar.File = function ( editor ) { var exporter = new THREE.OBJExporter(); - exportString( exporter.parse( object ) ); + exportString( exporter.parse( object ), 'model.obj' ); } ); options.add( option ); @@ -167,7 +167,7 @@ Menubar.File = function ( editor ) { var exporter = new THREE.STLExporter(); - exportString( exporter.parse( editor.scene ) ); + exportString( exporter.parse( editor.scene ), 'model.stl' ); } ); options.add( option ); @@ -217,6 +217,10 @@ Menubar.File = function ( editor ) { '', ' document.body.appendChild( player.dom );', '', + ' window.addEventListener( \'resize\', function () {', + ' player.setSize( window.innerWidth, window.innerHeight );', + ' } );', + '', ' } );', '', ' ', @@ -274,13 +278,16 @@ Menubar.File = function ( editor ) { // - var exportString = function ( output ) { + var exportString = function ( output, filename ) { var blob = new Blob( [ output ], { type: 'text/plain' } ); var objectURL = URL.createObjectURL( blob ); - window.open( objectURL, '_blank' ); - window.focus(); + var link = document.createElement( 'a' ); + link.href = objectURL; + link.download = filename || 'data.json'; + link.target = '_blank'; + link.click(); }; diff --git a/editor/js/Player.js b/editor/js/Player.js index be89a651ade271..3b8fe27fe35c85 100644 --- a/editor/js/Player.js +++ b/editor/js/Player.js @@ -19,7 +19,7 @@ var Player = function ( editor ) { if ( player.dom === undefined ) return; - player.setSize( container.dom.offsetWidth, container.dom.offsetHeight ); + player.setSize( container.dom.clientWidth, container.dom.clientHeight ); } ); @@ -28,7 +28,7 @@ var Player = function ( editor ) { container.setDisplay( '' ); player.load( editor.toJSON() ); - player.setSize( container.dom.offsetWidth, container.dom.offsetHeight ); + player.setSize( container.dom.clientWidth, container.dom.clientHeight ); player.play(); container.dom.appendChild( player.dom ); diff --git a/editor/js/Script.js b/editor/js/Script.js index 80fa696be5449b..6a6421f3a2639c 100644 --- a/editor/js/Script.js +++ b/editor/js/Script.js @@ -15,7 +15,7 @@ var Script = function ( editor ) { var header = new UI.Panel(); header.setPadding( '10px' ); container.add( header ); - + var title = new UI.Text().setColor( '#fff' ); header.add( title ); @@ -59,16 +59,99 @@ var Script = function ( editor ) { clearTimeout( delay ); delay = setTimeout( function () { - currentScript.source = codemirror.getValue(); + var value = codemirror.getValue(); + + if ( validate( value ) ) { + + currentScript.source = value; + signals.scriptChanged.dispatch( currentScript ); - signals.scriptChanged.dispatch( currentScript ); + } }, 300 ); }); + // validate + + var errorLines = []; + var widgets = []; + + var validate = function ( string ) { + + var syntax, errors; + + return codemirror.operation( function () { + + while ( errorLines.length > 0 ) { + + codemirror.removeLineClass( errorLines.shift(), 'background', 'errorLine' ); + + } + + while ( widgets.length > 0 ) { + + codemirror.removeLineWidget( widgets.shift() ); + + } + + // + + try { + + syntax = esprima.parse( string, { tolerant: true } ); + errors = syntax.errors; + + for ( var i = 0; i < errors.length; i ++ ) { + + var error = errors[ i ]; + + var message = document.createElement( 'div' ); + message.className = 'esprima-error'; + message.textContent = error.message.replace(/Line [0-9]+: /, ''); + + var lineNumber = error.lineNumber - 1; + errorLines.push( lineNumber ); + + codemirror.addLineClass( lineNumber, 'background', 'errorLine' ); + + var widget = codemirror.addLineWidget( + lineNumber, + message + ); + + widgets.push( widget ); + + } + + } catch ( error ) { + + var message = document.createElement( 'div' ); + message.className = 'esprima-error'; + message.textContent = error.message.replace(/Line [0-9]+: /, ''); + + var lineNumber = error.lineNumber - 1; + errorLines.push( lineNumber ); + + codemirror.addLineClass( lineNumber, 'background', 'errorLine' ); + + var widget = codemirror.addLineWidget( + lineNumber, + message + ); + + widgets.push( widget ); + + } + + return errorLines.length === 0; + + }); + + }; + // - + signals.editorCleared.add( function () { container.setDisplay( 'none' ); diff --git a/editor/js/Sidebar.Geometry.js b/editor/js/Sidebar.Geometry.js index 1fd62143bef2ad..e051c66a1b2274 100644 --- a/editor/js/Sidebar.Geometry.js +++ b/editor/js/Sidebar.Geometry.js @@ -17,6 +17,66 @@ Sidebar.Geometry = function ( editor ) { var geometryType = new UI.Text().setTextTransform( 'uppercase' ); container.addStatic( geometryType ); + + // Actions + + var objectActions = new UI.Select().setPosition('absolute').setRight( '8px' ).setFontSize( '11px' ); + objectActions.setOptions( { + + 'Actions': 'Actions', + 'Center': 'Center', + 'Flatten': 'Flatten' + + } ); + objectActions.onClick( function ( event ) { + + event.stopPropagation(); // Avoid panel collapsing + + } ); + objectActions.onChange( function ( event ) { + + var action = this.getValue(); + + var object = editor.selected; + var geometry = object.geometry; + + if ( confirm( action + ' ' + object.name + '?' ) === false ) return; + + switch ( action ) { + + case 'Center': + + var offset = geometry.center(); + + object.position.sub( offset ); + + editor.signals.geometryChanged.dispatch( geometry ); + editor.signals.objectChanged.dispatch( object ); + + break; + + case 'Flatten': + + geometry.applyMatrix( object.matrix ); + + object.position.set( 0, 0, 0 ); + object.rotation.set( 0, 0, 0 ); + object.scale.set( 1, 1, 1 ); + + editor.signals.geometryChanged.dispatch( geometry ); + editor.signals.objectChanged.dispatch( object ); + + break; + + } + + this.setValue( 'Actions' ); + + signals.objectChanged.dispatch( object ); + + } ); + container.addStatic( objectActions ); + container.add( new UI.Break() ); // uuid diff --git a/editor/js/Sidebar.Material.js b/editor/js/Sidebar.Material.js index 44c752f72910db..29822577da2a92 100644 --- a/editor/js/Sidebar.Material.js +++ b/editor/js/Sidebar.Material.js @@ -369,7 +369,7 @@ Sidebar.Material = function ( editor ) { var geometry = object.geometry; var material = object.material; - + var textureWarning = false; var objectHasUvs = false; @@ -436,8 +436,20 @@ Sidebar.Material = function ( editor ) { if ( material.vertexColors !== undefined ) { - material.vertexColors = parseInt( materialVertexColors.getValue() ); - material.needsUpdate = true; + var vertexColors = parseInt( materialVertexColors.getValue() ); + + if ( material.vertexColors !== vertexColors ) { + + if ( geometry instanceof THREE.Geometry ) { + + geometry.groupsNeedUpdate = true; + + } + + material.vertexColors = vertexColors; + material.needsUpdate = true; + + } } @@ -451,7 +463,7 @@ Sidebar.Material = function ( editor ) { var mapEnabled = materialMapEnabled.getValue() === true; - if ( objectHasUvs ) { + if ( objectHasUvs ) { material.map = mapEnabled ? materialMap.getValue() : null; material.needsUpdate = true; @@ -468,7 +480,7 @@ Sidebar.Material = function ( editor ) { var mapEnabled = materialAlphaMapEnabled.getValue() === true; - if ( objectHasUvs ) { + if ( objectHasUvs ) { material.alphaMap = mapEnabled ? materialAlphaMap.getValue() : null; material.needsUpdate = true; @@ -504,7 +516,7 @@ Sidebar.Material = function ( editor ) { var bumpMapEnabled = materialBumpMapEnabled.getValue() === true; - if ( objectHasUvs ) { + if ( objectHasUvs ) { material.bumpMap = bumpMapEnabled ? materialBumpMap.getValue() : null; material.bumpScale = materialBumpScale.getValue(); @@ -522,7 +534,7 @@ Sidebar.Material = function ( editor ) { var normalMapEnabled = materialNormalMapEnabled.getValue() === true; - if ( objectHasUvs ) { + if ( objectHasUvs ) { material.normalMap = normalMapEnabled ? materialNormalMap.getValue() : null; material.needsUpdate = true; @@ -539,7 +551,7 @@ Sidebar.Material = function ( editor ) { var specularMapEnabled = materialSpecularMapEnabled.getValue() === true; - if ( objectHasUvs ) { + if ( objectHasUvs ) { material.specularMap = specularMapEnabled ? materialSpecularMap.getValue() : null; material.needsUpdate = true; diff --git a/editor/js/Sidebar.Object3D.js b/editor/js/Sidebar.Object3D.js index d6f205f71fbb84..0aae11c0e456f6 100644 --- a/editor/js/Sidebar.Object3D.js +++ b/editor/js/Sidebar.Object3D.js @@ -18,6 +18,8 @@ Sidebar.Object3D = function ( editor ) { var objectType = new UI.Text().setTextTransform( 'uppercase' ); container.addStatic( objectType ); + // Actions + var objectActions = new UI.Select().setPosition('absolute').setRight( '8px' ).setFontSize( '11px' ); objectActions.setOptions( { @@ -29,7 +31,10 @@ Sidebar.Object3D = function ( editor ) { } ); objectActions.onClick( function ( event ) { - event.stopPropagation(); + event.stopPropagation(); // Avoid panel collapsing + + } ); + objectActions.onChange( function ( event ) { var object = editor.selected; @@ -48,14 +53,14 @@ Sidebar.Object3D = function ( editor ) { break; } - + this.setValue( 'Actions' ); signals.objectChanged.dispatch( object ); } ); container.addStatic( objectActions ); - + container.add( new UI.Break() ); // uuid @@ -81,7 +86,7 @@ Sidebar.Object3D = function ( editor ) { var objectNameRow = new UI.Panel(); var objectName = new UI.Input().setWidth( '150px' ).setFontSize( '12px' ).onChange( function () { - editor.setObjectName( editor.selected, objectName.getValue() ); + editor.nameObject( editor.selected, objectName.getValue() ); } ); @@ -228,6 +233,16 @@ Sidebar.Object3D = function ( editor ) { container.add( objectExponentRow ); + // decay + + var objectDecayRow = new UI.Panel(); + var objectDecay = new UI.Number().setRange( 0, Infinity ).onChange( update ); + + objectDecayRow.add( new UI.Text( 'Decay' ).setWidth( '90px' ) ); + objectDecayRow.add( objectDecay ); + + container.add( objectDecayRow ); + // visible var objectVisibleRow = new UI.Panel(); @@ -333,7 +348,7 @@ Sidebar.Object3D = function ( editor ) { if ( object.parent.id !== newParentId && object.id !== newParentId ) { - editor.parent( object, editor.scene.getObjectById( newParentId, true ) ); + editor.moveObject( object, editor.scene.getObjectById( newParentId ) ); } @@ -406,6 +421,12 @@ Sidebar.Object3D = function ( editor ) { } + if ( object.decay !== undefined ) { + + object.decay = objectDecay.getValue(); + + } + object.visible = objectVisible.getValue(); try { @@ -436,7 +457,8 @@ Sidebar.Object3D = function ( editor ) { 'groundColor': objectGroundColorRow, 'distance' : objectDistanceRow, 'angle' : objectAngleRow, - 'exponent' : objectExponentRow + 'exponent' : objectExponentRow, + 'decay' : objectDecayRow }; for ( var property in properties ) { @@ -585,6 +607,12 @@ Sidebar.Object3D = function ( editor ) { } + if ( object.decay !== undefined ) { + + objectDecay.setValue( object.decay ); + + } + objectVisible.setValue( object.visible ); try { diff --git a/editor/js/Sidebar.Scene.js b/editor/js/Sidebar.Scene.js index f0c155d2e5d553..7f5e32f41c9acc 100644 --- a/editor/js/Sidebar.Scene.js +++ b/editor/js/Sidebar.Scene.js @@ -19,7 +19,7 @@ Sidebar.Scene = function ( editor ) { var ignoreObjectSelectedSignal = false; - var outliner = new UI.FancySelect().setId( 'outliner' ); + var outliner = new UI.Outliner( editor ); outliner.onChange( function () { ignoreObjectSelectedSignal = true; @@ -134,7 +134,7 @@ Sidebar.Scene = function ( editor ) { var options = []; // options.push( { value: camera.id, html: ' ' + camera.name } ); - options.push( { value: scene.id, html: ' ' + scene.name } ); + options.push( { static: true, value: scene.id, html: ' ' + scene.name } ); ( function addObjects( objects, pad ) { diff --git a/editor/js/Sidebar.Script.js b/editor/js/Sidebar.Script.js index 92b7cda5b22249..dc7e5acae92d87 100644 --- a/editor/js/Sidebar.Script.js +++ b/editor/js/Sidebar.Script.js @@ -84,7 +84,7 @@ Sidebar.Script = function ( editor ) { } ); scriptsContainer.add( remove ); - + scriptsContainer.add( new UI.Break() ); } )( object, scripts[ i ] ) diff --git a/editor/js/Storage.js b/editor/js/Storage.js index e4e6551f1973de..8d8533c653836b 100644 --- a/editor/js/Storage.js +++ b/editor/js/Storage.js @@ -8,7 +8,7 @@ var Storage = function () { if ( indexedDB === undefined ) { console.warn( 'Storage: IndexedDB not available.' ); - return { init: function (){}, get: function (){}, set: function (){}, clear: function (){} }; + return { init: function () {}, get: function () {}, set: function () {}, clear: function () {} }; } var name = 'threejs-editor'; diff --git a/editor/js/Toolbar.js b/editor/js/Toolbar.js index 2905c2084b5354..d754748e0142eb 100644 --- a/editor/js/Toolbar.js +++ b/editor/js/Toolbar.js @@ -62,8 +62,6 @@ var Toolbar = function ( editor ) { } - update(); - return container; } diff --git a/editor/js/Viewport.js b/editor/js/Viewport.js index 79313be553b3cf..c64630885aa3a5 100644 --- a/editor/js/Viewport.js +++ b/editor/js/Viewport.js @@ -370,12 +370,6 @@ var Viewport = function ( editor ) { transformControls.update(); - if ( object.geometry !== undefined ) { - - selectionBox.update( object ); - - } - if ( object instanceof THREE.PerspectiveCamera ) { object.updateProjectionMatrix(); diff --git a/editor/js/libs/app.js b/editor/js/libs/app.js index 0618eeccff3247..04ec67ca354e3d 100644 --- a/editor/js/libs/app.js +++ b/editor/js/libs/app.js @@ -6,9 +6,13 @@ var APP = { Player: function () { + var scope = this; + var loader = new THREE.ObjectLoader(); var camera, scene, renderer; + var vr, controls; + var events = {}; this.dom = undefined; @@ -18,12 +22,15 @@ var APP = { this.load = function ( json ) { + vr = json.project.vr; + renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setClearColor( 0x000000 ); renderer.setPixelRatio( window.devicePixelRatio ); + this.dom = renderer.domElement; - camera = loader.parse( json.camera ); - scene = loader.parse( json.scene ); + this.setScene( loader.parse( json.scene ) ); + this.setCamera( loader.parse( json.camera ) ); events = { keydown: [], @@ -47,7 +54,7 @@ var APP = { var script = scripts[ i ]; - var functions = ( new Function( 'player', 'scene', 'keydown', 'keyup', 'mousedown', 'mouseup', 'mousemove', 'touchstart', 'touchend', 'touchmove', 'update', script.source + '\nreturn { keydown: keydown, keyup: keyup, mousedown: mousedown, mouseup: mouseup, mousemove: mousemove, touchstart: touchstart, touchend: touchend, touchmove: touchmove, update: update };' ).bind( object ) )( this, scene ); + var functions = ( new Function( 'player, scene, keydown, keyup, mousedown, mouseup, mousemove, touchstart, touchend, touchmove, update', script.source + '\nreturn { keydown: keydown, keyup: keyup, mousedown: mousedown, mouseup: mouseup, mousemove: mousemove, touchstart: touchstart, touchend: touchend, touchmove: touchmove, update: update };' ).bind( object ) )( this, scene ); for ( var name in functions ) { @@ -68,8 +75,6 @@ var APP = { } - this.dom = renderer.domElement; - }; this.setCamera = function ( value ) { @@ -78,10 +83,55 @@ var APP = { camera.aspect = this.width / this.height; camera.updateProjectionMatrix(); + + if ( vr === true ) { + + if ( camera.parent === undefined ) { + + // camera needs to be in the scene so camera2 matrix updates + + scene.add( camera ); + + } + + var camera2 = camera.clone(); + camera.add( camera2 ); + + camera = camera2; + + controls = new THREE.VRControls( camera ); + renderer = new THREE.VREffect( renderer ); + + document.addEventListener( 'keyup', function ( event ) { + + switch ( event.keyCode ) { + case 90: + controls.zeroSensor(); + break; + } + + } ); + + this.dom.addEventListener( 'dblclick', function () { + + renderer.setFullScreen( true ); + + } ); + + } + }; + this.setScene = function ( value ) { + + scene = value; + + }, + this.setSize = function ( width, height ) { + if ( renderer._fullScreen ) return; + this.width = width; this.height = height; @@ -102,16 +152,20 @@ var APP = { }; - var request; + var prevTime, request; var animate = function ( time ) { request = requestAnimationFrame( animate ); - dispatch( events.update, { time: time } ); + dispatch( events.update, { time: time, delta: time - prevTime } ); + + if ( vr ) controls.update(); renderer.render( scene, camera ); + prevTime = time; + }; this.play = function () { @@ -126,6 +180,7 @@ var APP = { document.addEventListener( 'touchmove', onDocumentTouchMove ); request = requestAnimationFrame( animate ); + prevTime = performance.now(); }; diff --git a/editor/js/libs/esprima.js b/editor/js/libs/esprima.js new file mode 100644 index 00000000000000..a1f80c83e13445 --- /dev/null +++ b/editor/js/libs/esprima.js @@ -0,0 +1,4156 @@ +/* + Copyright (C) 2013 Ariya Hidayat + Copyright (C) 2013 Thaddee Tyl + Copyright (C) 2013 Mathias Bynens + Copyright (C) 2012 Ariya Hidayat + Copyright (C) 2012 Mathias Bynens + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Yusuke Suzuki + Copyright (C) 2012 Arpad Borsos + Copyright (C) 2011 Ariya Hidayat + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // Rhino, and plain browser loading. + + /* istanbul ignore next */ + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.esprima = {})); + } +}(this, function (exports) { + 'use strict'; + + var Token, + TokenName, + FnExprTokens, + Syntax, + PlaceHolders, + PropertyKind, + Messages, + Regex, + source, + strict, + index, + lineNumber, + lineStart, + length, + lookahead, + state, + extra; + + Token = { + BooleanLiteral: 1, + EOF: 2, + Identifier: 3, + Keyword: 4, + NullLiteral: 5, + NumericLiteral: 6, + Punctuator: 7, + StringLiteral: 8, + RegularExpression: 9 + }; + + TokenName = {}; + TokenName[Token.BooleanLiteral] = 'Boolean'; + TokenName[Token.EOF] = ''; + TokenName[Token.Identifier] = 'Identifier'; + TokenName[Token.Keyword] = 'Keyword'; + TokenName[Token.NullLiteral] = 'Null'; + TokenName[Token.NumericLiteral] = 'Numeric'; + TokenName[Token.Punctuator] = 'Punctuator'; + TokenName[Token.StringLiteral] = 'String'; + TokenName[Token.RegularExpression] = 'RegularExpression'; + + // A function following one of those tokens is an expression. + FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', + 'return', 'case', 'delete', 'throw', 'void', + // assignment operators + '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', + '&=', '|=', '^=', ',', + // binary/unary operators + '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', + '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', + '<=', '<', '>', '!=', '!==']; + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + ArrowFunctionExpression: 'ArrowFunctionExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DoWhileStatement: 'DoWhileStatement', + DebuggerStatement: 'DebuggerStatement', + EmptyStatement: 'EmptyStatement', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement' + }; + + PlaceHolders = { + ArrowParameterPlaceHolder: { + type: 'ArrowParameterPlaceHolder' + } + }; + + PropertyKind = { + Data: 1, + Get: 2, + Set: 4 + }; + + // Error messages should be identical to V8. + Messages = { + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', + InvalidRegExp: 'Invalid regular expression', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', + MultipleDefaultsInSwitch: 'More than one default clause in switch statement', + NoCatchOrFinally: 'Missing catch or finally after try', + UnknownLabel: 'Undefined label \'%0\'', + Redeclaration: '%0 \'%1\' has already been declared', + IllegalContinue: 'Illegal continue statement', + IllegalBreak: 'Illegal break statement', + IllegalReturn: 'Illegal return statement', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictParamDupe: 'Strict mode function may not have duplicate parameter names', + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode' + }; + + // See also tools/generate-unicode-regex.py. + Regex = { + NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'), + NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') + }; + + // Ensure the condition is true, otherwise throw an error. + // This is only to have a better contract semantic, i.e. another safety net + // to catch a logic error. The condition shall be fulfilled in normal case. + // Do NOT use this to enforce a certain condition on any user input. + + function assert(condition, message) { + /* istanbul ignore if */ + if (!condition) { + throw new Error('ASSERT: ' + message); + } + } + + function isDecimalDigit(ch) { + return (ch >= 0x30 && ch <= 0x39); // 0..9 + } + + function isHexDigit(ch) { + return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; + } + + function isOctalDigit(ch) { + return '01234567'.indexOf(ch) >= 0; + } + + + // 7.2 White Space + + function isWhiteSpace(ch) { + return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || + (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0); + } + + // 7.3 Line Terminators + + function isLineTerminator(ch) { + return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029); + } + + // 7.6 Identifier Names and Identifiers + + function isIdentifierStart(ch) { + return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) + (ch >= 0x41 && ch <= 0x5A) || // A..Z + (ch >= 0x61 && ch <= 0x7A) || // a..z + (ch === 0x5C) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); + } + + function isIdentifierPart(ch) { + return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) + (ch >= 0x41 && ch <= 0x5A) || // A..Z + (ch >= 0x61 && ch <= 0x7A) || // a..z + (ch >= 0x30 && ch <= 0x39) || // 0..9 + (ch === 0x5C) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); + } + + // 7.6.1.2 Future Reserved Words + + function isFutureReservedWord(id) { + switch (id) { + case 'class': + case 'enum': + case 'export': + case 'extends': + case 'import': + case 'super': + return true; + default: + return false; + } + } + + function isStrictModeReservedWord(id) { + switch (id) { + case 'implements': + case 'interface': + case 'package': + case 'private': + case 'protected': + case 'public': + case 'static': + case 'yield': + case 'let': + return true; + default: + return false; + } + } + + function isRestrictedWord(id) { + return id === 'eval' || id === 'arguments'; + } + + // 7.6.1.1 Keywords + + function isKeyword(id) { + if (strict && isStrictModeReservedWord(id)) { + return true; + } + + // 'const' is specialized as Keyword in V8. + // 'yield' and 'let' are for compatibility with SpiderMonkey and ES.next. + // Some others are from future reserved words. + + switch (id.length) { + case 2: + return (id === 'if') || (id === 'in') || (id === 'do'); + case 3: + return (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let'); + case 4: + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); + case 5: + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); + case 6: + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); + case 7: + return (id === 'default') || (id === 'finally') || (id === 'extends'); + case 8: + return (id === 'function') || (id === 'continue') || (id === 'debugger'); + case 10: + return (id === 'instanceof'); + default: + return false; + } + } + + // 7.4 Comments + + function addComment(type, value, start, end, loc) { + var comment; + + assert(typeof start === 'number', 'Comment must have valid position'); + + // Because the way the actual token is scanned, often the comments + // (if any) are skipped twice during the lexical analysis. + // Thus, we need to skip adding a comment if the comment array already + // handled it. + if (state.lastCommentStart >= start) { + return; + } + state.lastCommentStart = start; + + comment = { + type: type, + value: value + }; + if (extra.range) { + comment.range = [start, end]; + } + if (extra.loc) { + comment.loc = loc; + } + extra.comments.push(comment); + if (extra.attachComment) { + extra.leadingComments.push(comment); + extra.trailingComments.push(comment); + } + } + + function skipSingleLineComment(offset) { + var start, loc, ch, comment; + + start = index - offset; + loc = { + start: { + line: lineNumber, + column: index - lineStart - offset + } + }; + + while (index < length) { + ch = source.charCodeAt(index); + ++index; + if (isLineTerminator(ch)) { + if (extra.comments) { + comment = source.slice(start + offset, index - 1); + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + addComment('Line', comment, start, index - 1, loc); + } + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + return; + } + } + + if (extra.comments) { + comment = source.slice(start + offset, index); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Line', comment, start, index, loc); + } + } + + function skipMultiLineComment() { + var start, loc, ch, comment; + + if (extra.comments) { + start = index - 2; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 + } + }; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (isLineTerminator(ch)) { + if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) { + ++index; + } + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwUnexpectedToken(); + } + } else if (ch === 0x2A) { + // Block comment ends with '*/'. + if (source.charCodeAt(index + 1) === 0x2F) { + ++index; + ++index; + if (extra.comments) { + comment = source.slice(start + 2, index - 2); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); + } + return; + } + ++index; + } else { + ++index; + } + } + + throwUnexpectedToken(); + } + + function skipComment() { + var ch, start; + + start = (index === 0); + while (index < length) { + ch = source.charCodeAt(index); + + if (isWhiteSpace(ch)) { + ++index; + } else if (isLineTerminator(ch)) { + ++index; + if (ch === 0x0D && source.charCodeAt(index) === 0x0A) { + ++index; + } + ++lineNumber; + lineStart = index; + start = true; + } else if (ch === 0x2F) { // U+002F is '/' + ch = source.charCodeAt(index + 1); + if (ch === 0x2F) { + ++index; + ++index; + skipSingleLineComment(2); + start = true; + } else if (ch === 0x2A) { // U+002A is '*' + ++index; + ++index; + skipMultiLineComment(); + } else { + break; + } + } else if (start && ch === 0x2D) { // U+002D is '-' + // U+003E is '>' + if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) { + // '-->' is a single-line comment + index += 3; + skipSingleLineComment(3); + } else { + break; + } + } else if (ch === 0x3C) { // U+003C is '<' + if (source.slice(index + 1, index + 4) === '!--') { + ++index; // `<` + ++index; // `!` + ++index; // `-` + ++index; // `-` + skipSingleLineComment(4); + } else { + break; + } + } else { + break; + } + } + } + + function scanHexEscape(prefix) { + var i, len, ch, code = 0; + + len = (prefix === 'u') ? 4 : 2; + for (i = 0; i < len; ++i) { + if (index < length && isHexDigit(source[index])) { + ch = source[index++]; + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } else { + return ''; + } + } + return String.fromCharCode(code); + } + + function scanUnicodeCodePointEscape() { + var ch, code, cu1, cu2; + + ch = source[index]; + code = 0; + + // At least, one hex digit is required. + if (ch === '}') { + throwUnexpectedToken(); + } + + while (index < length) { + ch = source[index++]; + if (!isHexDigit(ch)) { + break; + } + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } + + if (code > 0x10FFFF || ch !== '}') { + throwUnexpectedToken(); + } + + // UTF-16 Encoding + if (code <= 0xFFFF) { + return String.fromCharCode(code); + } + cu1 = ((code - 0x10000) >> 10) + 0xD800; + cu2 = ((code - 0x10000) & 1023) + 0xDC00; + return String.fromCharCode(cu1, cu2); + } + + function getEscapedIdentifier() { + var ch, id; + + ch = source.charCodeAt(index++); + id = String.fromCharCode(ch); + + // '\u' (U+005C, U+0075) denotes an escaped character. + if (ch === 0x5C) { + if (source.charCodeAt(index) !== 0x75) { + throwUnexpectedToken(); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { + throwUnexpectedToken(); + } + id = ch; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (!isIdentifierPart(ch)) { + break; + } + ++index; + id += String.fromCharCode(ch); + + // '\u' (U+005C, U+0075) denotes an escaped character. + if (ch === 0x5C) { + id = id.substr(0, id.length - 1); + if (source.charCodeAt(index) !== 0x75) { + throwUnexpectedToken(); + } + ++index; + ch = scanHexEscape('u'); + if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { + throwUnexpectedToken(); + } + id += ch; + } + } + + return id; + } + + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source.charCodeAt(index); + if (ch === 0x5C) { + // Blackslash (U+005C) marks Unicode escape sequence. + index = start; + return getEscapedIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } + } + + return source.slice(start, index); + } + + function scanIdentifier() { + var start, id, type; + + start = index; + + // Backslash (U+005C) starts an escaped character. + id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; + } + + return { + type: type, + value: id, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + + // 7.7 Punctuators + + function scanPunctuator() { + var start = index, + code = source.charCodeAt(index), + code2, + ch1 = source[index], + ch2, + ch3, + ch4; + + switch (code) { + + // Check for most common single-character punctuators. + case 0x2E: // . dot + case 0x28: // ( open bracket + case 0x29: // ) close bracket + case 0x3B: // ; semicolon + case 0x2C: // , comma + case 0x7B: // { open curly brace + case 0x7D: // } close curly brace + case 0x5B: // [ + case 0x5D: // ] + case 0x3A: // : + case 0x3F: // ? + case 0x7E: // ~ + ++index; + if (extra.tokenize) { + if (code === 0x28) { + extra.openParenToken = extra.tokens.length; + } else if (code === 0x7B) { + extra.openCurlyToken = extra.tokens.length; + } + } + return { + type: Token.Punctuator, + value: String.fromCharCode(code), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + + default: + code2 = source.charCodeAt(index + 1); + + // '=' (U+003D) marks an assignment or comparison operator. + if (code2 === 0x3D) { + switch (code) { + case 0x2B: // + + case 0x2D: // - + case 0x2F: // / + case 0x3C: // < + case 0x3E: // > + case 0x5E: // ^ + case 0x7C: // | + case 0x25: // % + case 0x26: // & + case 0x2A: // * + index += 2; + return { + type: Token.Punctuator, + value: String.fromCharCode(code) + String.fromCharCode(code2), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + + case 0x21: // ! + case 0x3D: // = + index += 2; + + // !== and === + if (source.charCodeAt(index) === 0x3D) { + ++index; + } + return { + type: Token.Punctuator, + value: source.slice(start, index), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + } + } + + // 4-character punctuator: >>>= + + ch4 = source.substr(index, 4); + + if (ch4 === '>>>=') { + index += 4; + return { + type: Token.Punctuator, + value: ch4, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // 3-character punctuators: === !== >>> <<= >>= + + ch3 = ch4.substr(0, 3); + + if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') { + index += 3; + return { + type: Token.Punctuator, + value: ch3, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // Other 2-character punctuators: ++ -- << >> && || + ch2 = ch3.substr(0, 2); + + if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') { + index += 2; + return { + type: Token.Punctuator, + value: ch2, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // 1-character punctuators: < > = ! + - * % & | ^ / + + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + ++index; + return { + type: Token.Punctuator, + value: ch1, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + throwUnexpectedToken(); + } + + // 7.8.3 Numeric Literals + + function scanHexLiteral(start) { + var number = ''; + + while (index < length) { + if (!isHexDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + throwUnexpectedToken(); + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwUnexpectedToken(); + } + + return { + type: Token.NumericLiteral, + value: parseInt('0x' + number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function scanBinaryLiteral(start) { + var ch, number; + + number = ''; + + while (index < length) { + ch = source[index]; + if (ch !== '0' && ch !== '1') { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + // only 0b or 0B + throwUnexpectedToken(); + } + + if (index < length) { + ch = source.charCodeAt(index); + /* istanbul ignore else */ + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwUnexpectedToken(); + } + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 2), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function scanOctalLiteral(prefix, start) { + var number, octal; + + if (isOctalDigit(prefix)) { + octal = true; + number = '0' + source[index++]; + } else { + octal = false; + ++index; + number = ''; + } + + while (index < length) { + if (!isOctalDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (!octal && number.length === 0) { + // only 0o or 0O + throwUnexpectedToken(); + } + + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { + throwUnexpectedToken(); + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: octal, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function isImplicitOctalLiteral() { + var i, ch; + + // Implicit octal, unless there is a non-octal digit. + // (Annex B.1.1 on Numeric Literals) + for (i = index + 1; i < length; ++i) { + ch = source[i]; + if (ch === '8' || ch === '9') { + return false; + } + if (!isOctalDigit(ch)) { + return true; + } + } + + return true; + } + + function scanNumericLiteral() { + var number, start, ch; + + ch = source[index]; + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), + 'Numeric literal must start with a decimal digit or a decimal point'); + + start = index; + number = ''; + if (ch !== '.') { + number = source[index++]; + ch = source[index]; + + // Hex number starts with '0x'. + // Octal number starts with '0'. + // Octal number in ES6 starts with '0o'. + // Binary number in ES6 starts with '0b'. + if (number === '0') { + if (ch === 'x' || ch === 'X') { + ++index; + return scanHexLiteral(start); + } + if (ch === 'b' || ch === 'B') { + ++index; + return scanBinaryLiteral(start); + } + if (ch === 'o' || ch === 'O') { + return scanOctalLiteral(ch, start); + } + + if (isOctalDigit(ch)) { + if (isImplicitOctalLiteral()) { + return scanOctalLiteral(ch, start); + } + } + } + + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === '.') { + number += source[index++]; + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + ch = source[index]; + } + + if (ch === 'e' || ch === 'E') { + number += source[index++]; + + ch = source[index]; + if (ch === '+' || ch === '-') { + number += source[index++]; + } + if (isDecimalDigit(source.charCodeAt(index))) { + while (isDecimalDigit(source.charCodeAt(index))) { + number += source[index++]; + } + } else { + throwUnexpectedToken(); + } + } + + if (isIdentifierStart(source.charCodeAt(index))) { + throwUnexpectedToken(); + } + + return { + type: Token.NumericLiteral, + value: parseFloat(number), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + // 7.8.4 String Literals + + function scanStringLiteral() { + var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart; + startLineNumber = lineNumber; + startLineStart = lineStart; + + quote = source[index]; + assert((quote === '\'' || quote === '"'), + 'String literal must starts with a quote'); + + start = index; + ++index; + + while (index < length) { + ch = source[index++]; + + if (ch === quote) { + quote = ''; + break; + } else if (ch === '\\') { + ch = source[index++]; + if (!ch || !isLineTerminator(ch.charCodeAt(0))) { + switch (ch) { + case 'u': + case 'x': + if (source[index] === '{') { + ++index; + str += scanUnicodeCodePointEscape(); + } else { + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } + } + break; + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case 'v': + str += '\x0B'; + break; + + default: + if (isOctalDigit(ch)) { + code = '01234567'.indexOf(ch); + + // \0 is not octal escape sequence + if (code !== 0) { + octal = true; + } + + if (index < length && isOctalDigit(source[index])) { + octal = true; + code = code * 8 + '01234567'.indexOf(source[index++]); + + // 3 digits are only allowed when string starts + // with 0, 1, 2, 3 + if ('0123'.indexOf(ch) >= 0 && + index < length && + isOctalDigit(source[index])) { + code = code * 8 + '01234567'.indexOf(source[index++]); + } + } + str += String.fromCharCode(code); + } else { + str += ch; + } + break; + } + } else { + ++lineNumber; + if (ch === '\r' && source[index] === '\n') { + ++index; + } + lineStart = index; + } + } else if (isLineTerminator(ch.charCodeAt(0))) { + break; + } else { + str += ch; + } + } + + if (quote !== '') { + throwUnexpectedToken(); + } + + return { + type: Token.StringLiteral, + value: str, + octal: octal, + startLineNumber: startLineNumber, + startLineStart: startLineStart, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function testRegExp(pattern, flags) { + var tmp = pattern, + value; + + if (flags.indexOf('u') >= 0) { + // Replace each astral symbol and every Unicode code point + // escape sequence with a single ASCII symbol to avoid throwing on + // regular expressions that are only valid in combination with the + // `/u` flag. + // Note: replacing with the ASCII symbol `x` might cause false + // negatives in unlikely scenarios. For example, `[\u{61}-b]` is a + // perfectly valid pattern that is equivalent to `[a-b]`, but it + // would be replaced by `[x-b]` which throws an error. + tmp = tmp + .replace(/\\u\{([0-9a-fA-F]+)\}/g, function ($0, $1) { + if (parseInt($1, 16) <= 0x10FFFF) { + return 'x'; + } + throwError(Messages.InvalidRegExp); + }) + .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 'x'); + } + + // First, detect invalid regular expressions. + try { + value = new RegExp(tmp); + } catch (e) { + throwError(Messages.InvalidRegExp); + } + + // Return a regular expression object for this pattern-flag pair, or + // `null` in case the current environment doesn't support the flags it + // uses. + try { + return new RegExp(pattern, flags); + } catch (exception) { + return null; + } + } + + function scanRegExpBody() { + var ch, str, classMarker, terminated, body; + + ch = source[index]; + assert(ch === '/', 'Regular expression literal must start with a slash'); + str = source[index++]; + + classMarker = false; + terminated = false; + while (index < length) { + ch = source[index++]; + str += ch; + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch.charCodeAt(0))) { + throwError(Messages.UnterminatedRegExp); + } + str += ch; + } else if (isLineTerminator(ch.charCodeAt(0))) { + throwError(Messages.UnterminatedRegExp); + } else if (classMarker) { + if (ch === ']') { + classMarker = false; + } + } else { + if (ch === '/') { + terminated = true; + break; + } else if (ch === '[') { + classMarker = true; + } + } + } + + if (!terminated) { + throwError(Messages.UnterminatedRegExp); + } + + // Exclude leading and trailing slash. + body = str.substr(1, str.length - 2); + return { + value: body, + literal: str + }; + } + + function scanRegExpFlags() { + var ch, str, flags, restore; + + str = ''; + flags = ''; + while (index < length) { + ch = source[index]; + if (!isIdentifierPart(ch.charCodeAt(0))) { + break; + } + + ++index; + if (ch === '\\' && index < length) { + ch = source[index]; + if (ch === 'u') { + ++index; + restore = index; + ch = scanHexEscape('u'); + if (ch) { + flags += ch; + for (str += '\\u'; restore < index; ++restore) { + str += source[restore]; + } + } else { + index = restore; + flags += 'u'; + str += '\\u'; + } + tolerateUnexpectedToken(); + } else { + str += '\\'; + tolerateUnexpectedToken(); + } + } else { + flags += ch; + str += ch; + } + } + + return { + value: flags, + literal: str + }; + } + + function scanRegExp() { + var start, body, flags, value; + + lookahead = null; + skipComment(); + start = index; + + body = scanRegExpBody(); + flags = scanRegExpFlags(); + value = testRegExp(body.value, flags.value); + + if (extra.tokenize) { + return { + type: Token.RegularExpression, + value: value, + regex: { + pattern: body.value, + flags: flags.value + }, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + return { + literal: body.literal + flags.literal, + value: value, + regex: { + pattern: body.value, + flags: flags.value + }, + start: start, + end: index + }; + } + + function collectRegex() { + var pos, loc, regex, token; + + skipComment(); + + pos = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + regex = scanRegExp(); + + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + /* istanbul ignore next */ + if (!extra.tokenize) { + // Pop the previous token, which is likely '/' or '/=' + if (extra.tokens.length > 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + regex: regex.regex, + range: [pos, index], + loc: loc + }); + } + + return regex; + } + + function isIdentifierName(token) { + return token.type === Token.Identifier || + token.type === Token.Keyword || + token.type === Token.BooleanLiteral || + token.type === Token.NullLiteral; + } + + function advanceSlash() { + var prevToken, + checkToken; + // Using the following algorithm: + // https://github.com/mozilla/sweet.js/wiki/design + prevToken = extra.tokens[extra.tokens.length - 1]; + if (!prevToken) { + // Nothing before that: it cannot be a division. + return collectRegex(); + } + if (prevToken.type === 'Punctuator') { + if (prevToken.value === ']') { + return scanPunctuator(); + } + if (prevToken.value === ')') { + checkToken = extra.tokens[extra.openParenToken - 1]; + if (checkToken && + checkToken.type === 'Keyword' && + (checkToken.value === 'if' || + checkToken.value === 'while' || + checkToken.value === 'for' || + checkToken.value === 'with')) { + return collectRegex(); + } + return scanPunctuator(); + } + if (prevToken.value === '}') { + // Dividing a function by anything makes little sense, + // but we have to check for that. + if (extra.tokens[extra.openCurlyToken - 3] && + extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') { + // Anonymous function. + checkToken = extra.tokens[extra.openCurlyToken - 4]; + if (!checkToken) { + return scanPunctuator(); + } + } else if (extra.tokens[extra.openCurlyToken - 4] && + extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { + // Named function. + checkToken = extra.tokens[extra.openCurlyToken - 5]; + if (!checkToken) { + return collectRegex(); + } + } else { + return scanPunctuator(); + } + // checkToken determines whether the function is + // a declaration or an expression. + if (FnExprTokens.indexOf(checkToken.value) >= 0) { + // It is an expression. + return scanPunctuator(); + } + // It is a declaration. + return collectRegex(); + } + return collectRegex(); + } + if (prevToken.type === 'Keyword' && prevToken.value !== 'this') { + return collectRegex(); + } + return scanPunctuator(); + } + + function advance() { + var ch; + + skipComment(); + + if (index >= length) { + return { + type: Token.EOF, + lineNumber: lineNumber, + lineStart: lineStart, + start: index, + end: index + }; + } + + ch = source.charCodeAt(index); + + if (isIdentifierStart(ch)) { + return scanIdentifier(); + } + + // Very common: ( and ) and ; + if (ch === 0x28 || ch === 0x29 || ch === 0x3B) { + return scanPunctuator(); + } + + // String literal starts with single quote (U+0027) or double quote (U+0022). + if (ch === 0x27 || ch === 0x22) { + return scanStringLiteral(); + } + + + // Dot (.) U+002E can also start a floating-point number, hence the need + // to check the next character. + if (ch === 0x2E) { + if (isDecimalDigit(source.charCodeAt(index + 1))) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + + if (isDecimalDigit(ch)) { + return scanNumericLiteral(); + } + + // Slash (/) U+002F can also start a regex. + if (extra.tokenize && ch === 0x2F) { + return advanceSlash(); + } + + return scanPunctuator(); + } + + function collectToken() { + var loc, token, value, entry; + + skipComment(); + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + token = advance(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + if (token.type !== Token.EOF) { + value = source.slice(token.start, token.end); + entry = { + type: TokenName[token.type], + value: value, + range: [token.start, token.end], + loc: loc + }; + if (token.regex) { + entry.regex = { + pattern: token.regex.pattern, + flags: token.regex.flags + }; + } + extra.tokens.push(entry); + } + + return token; + } + + function lex() { + var token; + + token = lookahead; + index = token.end; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); + + index = token.end; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + return token; + } + + function peek() { + var pos, line, start; + + pos = index; + line = lineNumber; + start = lineStart; + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); + index = pos; + lineNumber = line; + lineStart = start; + } + + function Position() { + this.line = lineNumber; + this.column = index - lineStart; + } + + function SourceLocation() { + this.start = new Position(); + this.end = null; + } + + function WrappingSourceLocation(startToken) { + if (startToken.type === Token.StringLiteral) { + this.start = { + line: startToken.startLineNumber, + column: startToken.start - startToken.startLineStart + }; + } else { + this.start = { + line: startToken.lineNumber, + column: startToken.start - startToken.lineStart + }; + } + this.end = null; + } + + function Node() { + // Skip comment. + index = lookahead.start; + if (lookahead.type === Token.StringLiteral) { + lineNumber = lookahead.startLineNumber; + lineStart = lookahead.startLineStart; + } else { + lineNumber = lookahead.lineNumber; + lineStart = lookahead.lineStart; + } + if (extra.range) { + this.range = [index, 0]; + } + if (extra.loc) { + this.loc = new SourceLocation(); + } + } + + function WrappingNode(startToken) { + if (extra.range) { + this.range = [startToken.start, 0]; + } + if (extra.loc) { + this.loc = new WrappingSourceLocation(startToken); + } + } + + WrappingNode.prototype = Node.prototype = { + + processComment: function () { + var lastChild, + leadingComments, + trailingComments, + bottomRight = extra.bottomRightStack, + i, + comment, + last = bottomRight[bottomRight.length - 1]; + + if (this.type === Syntax.Program) { + if (this.body.length > 0) { + return; + } + } + + if (extra.trailingComments.length > 0) { + trailingComments = []; + for (i = extra.trailingComments.length - 1; i >= 0; --i) { + comment = extra.trailingComments[i]; + if (comment.range[0] >= this.range[1]) { + trailingComments.unshift(comment); + extra.trailingComments.splice(i, 1); + } + } + extra.trailingComments = []; + } else { + if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) { + trailingComments = last.trailingComments; + delete last.trailingComments; + } + } + + // Eating the stack. + if (last) { + while (last && last.range[0] >= this.range[0]) { + lastChild = last; + last = bottomRight.pop(); + } + } + + if (lastChild) { + if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= this.range[0]) { + this.leadingComments = lastChild.leadingComments; + lastChild.leadingComments = undefined; + } + } else if (extra.leadingComments.length > 0) { + leadingComments = []; + for (i = extra.leadingComments.length - 1; i >= 0; --i) { + comment = extra.leadingComments[i]; + if (comment.range[1] <= this.range[0]) { + leadingComments.unshift(comment); + extra.leadingComments.splice(i, 1); + } + } + } + + + if (leadingComments && leadingComments.length > 0) { + this.leadingComments = leadingComments; + } + if (trailingComments && trailingComments.length > 0) { + this.trailingComments = trailingComments; + } + + bottomRight.push(this); + }, + + finish: function () { + if (extra.range) { + this.range[1] = index; + } + if (extra.loc) { + this.loc.end = new Position(); + if (extra.source) { + this.loc.source = extra.source; + } + } + + if (extra.attachComment) { + this.processComment(); + } + }, + + finishArrayExpression: function (elements) { + this.type = Syntax.ArrayExpression; + this.elements = elements; + this.finish(); + return this; + }, + + finishArrowFunctionExpression: function (params, defaults, body, expression) { + this.type = Syntax.ArrowFunctionExpression; + this.id = null; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = expression; + this.finish(); + return this; + }, + + finishAssignmentExpression: function (operator, left, right) { + this.type = Syntax.AssignmentExpression; + this.operator = operator; + this.left = left; + this.right = right; + this.finish(); + return this; + }, + + finishBinaryExpression: function (operator, left, right) { + this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression; + this.operator = operator; + this.left = left; + this.right = right; + this.finish(); + return this; + }, + + finishBlockStatement: function (body) { + this.type = Syntax.BlockStatement; + this.body = body; + this.finish(); + return this; + }, + + finishBreakStatement: function (label) { + this.type = Syntax.BreakStatement; + this.label = label; + this.finish(); + return this; + }, + + finishCallExpression: function (callee, args) { + this.type = Syntax.CallExpression; + this.callee = callee; + this.arguments = args; + this.finish(); + return this; + }, + + finishCatchClause: function (param, body) { + this.type = Syntax.CatchClause; + this.param = param; + this.body = body; + this.finish(); + return this; + }, + + finishConditionalExpression: function (test, consequent, alternate) { + this.type = Syntax.ConditionalExpression; + this.test = test; + this.consequent = consequent; + this.alternate = alternate; + this.finish(); + return this; + }, + + finishContinueStatement: function (label) { + this.type = Syntax.ContinueStatement; + this.label = label; + this.finish(); + return this; + }, + + finishDebuggerStatement: function () { + this.type = Syntax.DebuggerStatement; + this.finish(); + return this; + }, + + finishDoWhileStatement: function (body, test) { + this.type = Syntax.DoWhileStatement; + this.body = body; + this.test = test; + this.finish(); + return this; + }, + + finishEmptyStatement: function () { + this.type = Syntax.EmptyStatement; + this.finish(); + return this; + }, + + finishExpressionStatement: function (expression) { + this.type = Syntax.ExpressionStatement; + this.expression = expression; + this.finish(); + return this; + }, + + finishForStatement: function (init, test, update, body) { + this.type = Syntax.ForStatement; + this.init = init; + this.test = test; + this.update = update; + this.body = body; + this.finish(); + return this; + }, + + finishForInStatement: function (left, right, body) { + this.type = Syntax.ForInStatement; + this.left = left; + this.right = right; + this.body = body; + this.each = false; + this.finish(); + return this; + }, + + finishFunctionDeclaration: function (id, params, defaults, body) { + this.type = Syntax.FunctionDeclaration; + this.id = id; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = false; + this.finish(); + return this; + }, + + finishFunctionExpression: function (id, params, defaults, body) { + this.type = Syntax.FunctionExpression; + this.id = id; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = false; + this.finish(); + return this; + }, + + finishIdentifier: function (name) { + this.type = Syntax.Identifier; + this.name = name; + this.finish(); + return this; + }, + + finishIfStatement: function (test, consequent, alternate) { + this.type = Syntax.IfStatement; + this.test = test; + this.consequent = consequent; + this.alternate = alternate; + this.finish(); + return this; + }, + + finishLabeledStatement: function (label, body) { + this.type = Syntax.LabeledStatement; + this.label = label; + this.body = body; + this.finish(); + return this; + }, + + finishLiteral: function (token) { + this.type = Syntax.Literal; + this.value = token.value; + this.raw = source.slice(token.start, token.end); + if (token.regex) { + this.regex = token.regex; + } + this.finish(); + return this; + }, + + finishMemberExpression: function (accessor, object, property) { + this.type = Syntax.MemberExpression; + this.computed = accessor === '['; + this.object = object; + this.property = property; + this.finish(); + return this; + }, + + finishNewExpression: function (callee, args) { + this.type = Syntax.NewExpression; + this.callee = callee; + this.arguments = args; + this.finish(); + return this; + }, + + finishObjectExpression: function (properties) { + this.type = Syntax.ObjectExpression; + this.properties = properties; + this.finish(); + return this; + }, + + finishPostfixExpression: function (operator, argument) { + this.type = Syntax.UpdateExpression; + this.operator = operator; + this.argument = argument; + this.prefix = false; + this.finish(); + return this; + }, + + finishProgram: function (body) { + this.type = Syntax.Program; + this.body = body; + this.finish(); + return this; + }, + + finishProperty: function (kind, key, value, method, shorthand) { + this.type = Syntax.Property; + this.key = key; + this.value = value; + this.kind = kind; + this.method = method; + this.shorthand = shorthand; + this.finish(); + return this; + }, + + finishReturnStatement: function (argument) { + this.type = Syntax.ReturnStatement; + this.argument = argument; + this.finish(); + return this; + }, + + finishSequenceExpression: function (expressions) { + this.type = Syntax.SequenceExpression; + this.expressions = expressions; + this.finish(); + return this; + }, + + finishSwitchCase: function (test, consequent) { + this.type = Syntax.SwitchCase; + this.test = test; + this.consequent = consequent; + this.finish(); + return this; + }, + + finishSwitchStatement: function (discriminant, cases) { + this.type = Syntax.SwitchStatement; + this.discriminant = discriminant; + this.cases = cases; + this.finish(); + return this; + }, + + finishThisExpression: function () { + this.type = Syntax.ThisExpression; + this.finish(); + return this; + }, + + finishThrowStatement: function (argument) { + this.type = Syntax.ThrowStatement; + this.argument = argument; + this.finish(); + return this; + }, + + finishTryStatement: function (block, guardedHandlers, handlers, finalizer) { + this.type = Syntax.TryStatement; + this.block = block; + this.guardedHandlers = guardedHandlers; + this.handlers = handlers; + this.finalizer = finalizer; + this.finish(); + return this; + }, + + finishUnaryExpression: function (operator, argument) { + this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression; + this.operator = operator; + this.argument = argument; + this.prefix = true; + this.finish(); + return this; + }, + + finishVariableDeclaration: function (declarations, kind) { + this.type = Syntax.VariableDeclaration; + this.declarations = declarations; + this.kind = kind; + this.finish(); + return this; + }, + + finishVariableDeclarator: function (id, init) { + this.type = Syntax.VariableDeclarator; + this.id = id; + this.init = init; + this.finish(); + return this; + }, + + finishWhileStatement: function (test, body) { + this.type = Syntax.WhileStatement; + this.test = test; + this.body = body; + this.finish(); + return this; + }, + + finishWithStatement: function (object, body) { + this.type = Syntax.WithStatement; + this.object = object; + this.body = body; + this.finish(); + return this; + } + }; + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; + } + + function createError(line, pos, description) { + var error = new Error('Line ' + line + ': ' + description); + error.index = pos; + error.lineNumber = line; + error.column = pos - lineStart + 1; + error.description = description; + return error; + } + + // Throw an exception + + function throwError(messageFormat) { + var args, msg; + + args = Array.prototype.slice.call(arguments, 1); + msg = messageFormat.replace(/%(\d)/g, + function (whole, idx) { + assert(idx < args.length, 'Message reference must be in range'); + return args[idx]; + } + ); + + throw createError(lineNumber, index, msg); + } + + function tolerateError(messageFormat) { + var args, msg, error; + + args = Array.prototype.slice.call(arguments, 1); + /* istanbul ignore next */ + msg = messageFormat.replace(/%(\d)/g, + function (whole, idx) { + assert(idx < args.length, 'Message reference must be in range'); + return args[idx]; + } + ); + + error = createError(lineNumber, index, msg); + if (extra.errors) { + extra.errors.push(error); + } else { + throw error; + } + } + + // Throw an exception because of the token. + + function unexpectedTokenError(token, message) { + var msg = Messages.UnexpectedToken; + + if (token) { + msg = message ? message : + (token.type === Token.EOF) ? Messages.UnexpectedEOS : + (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier : + (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber : + (token.type === Token.StringLiteral) ? Messages.UnexpectedString : + Messages.UnexpectedToken; + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + msg = Messages.UnexpectedReserved; + } else if (strict && isStrictModeReservedWord(token.value)) { + msg = Messages.StrictReservedWord; + } + } + } + + msg = msg.replace('%0', token ? token.value : 'ILLEGAL'); + + return (token && typeof token.lineNumber === 'number') ? + createError(token.lineNumber, token.start, msg) : + createError(lineNumber, index, msg); + } + + function throwUnexpectedToken(token, message) { + throw unexpectedTokenError(token, message); + } + + function tolerateUnexpectedToken(token, message) { + var error = unexpectedTokenError(token, message); + if (extra.errors) { + extra.errors.push(error); + } else { + throw error; + } + } + + // Expect the next token to match the specified punctuator. + // If not, an exception will be thrown. + + function expect(value) { + var token = lex(); + if (token.type !== Token.Punctuator || token.value !== value) { + throwUnexpectedToken(token); + } + } + + /** + * @name expectCommaSeparator + * @description Quietly expect a comma when in tolerant mode, otherwise delegates + * to expect(value) + * @since 2.0 + */ + function expectCommaSeparator() { + var token; + + if (extra.errors) { + token = lookahead; + if (token.type === Token.Punctuator && token.value === ',') { + lex(); + } else if (token.type === Token.Punctuator && token.value === ';') { + lex(); + tolerateUnexpectedToken(token); + } else { + tolerateUnexpectedToken(token, Messages.UnexpectedToken); + } + } else { + expect(','); + } + } + + // Expect the next token to match the specified keyword. + // If not, an exception will be thrown. + + function expectKeyword(keyword) { + var token = lex(); + if (token.type !== Token.Keyword || token.value !== keyword) { + throwUnexpectedToken(token); + } + } + + // Return true if the next token matches the specified punctuator. + + function match(value) { + return lookahead.type === Token.Punctuator && lookahead.value === value; + } + + // Return true if the next token matches the specified keyword + + function matchKeyword(keyword) { + return lookahead.type === Token.Keyword && lookahead.value === keyword; + } + + // Return true if the next token is an assignment operator + + function matchAssign() { + var op; + + if (lookahead.type !== Token.Punctuator) { + return false; + } + op = lookahead.value; + return op === '=' || + op === '*=' || + op === '/=' || + op === '%=' || + op === '+=' || + op === '-=' || + op === '<<=' || + op === '>>=' || + op === '>>>=' || + op === '&=' || + op === '^=' || + op === '|='; + } + + function consumeSemicolon() { + var line, oldIndex = index, oldLineNumber = lineNumber, + oldLineStart = lineStart, oldLookahead = lookahead; + + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(index) === 0x3B || match(';')) { + lex(); + return; + } + + line = lineNumber; + skipComment(); + if (lineNumber !== line) { + index = oldIndex; + lineNumber = oldLineNumber; + lineStart = oldLineStart; + lookahead = oldLookahead; + return; + } + + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpectedToken(lookahead); + } + } + + // Return true if provided expression is LeftHandSideExpression + + function isLeftHandSide(expr) { + return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; + } + + // 11.1.4 Array Initialiser + + function parseArrayInitialiser() { + var elements = [], node = new Node(); + + expect('['); + + while (!match(']')) { + if (match(',')) { + lex(); + elements.push(null); + } else { + elements.push(parseAssignmentExpression()); + + if (!match(']')) { + expect(','); + } + } + } + + lex(); + + return node.finishArrayExpression(elements); + } + + // 11.1.5 Object Initialiser + + function parsePropertyFunction(param, first) { + var previousStrict, body, node = new Node(); + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (first && strict && isRestrictedWord(param[0].name)) { + tolerateUnexpectedToken(first, Messages.StrictParamName); + } + strict = previousStrict; + return node.finishFunctionExpression(null, param, [], body); + } + + function parsePropertyMethodFunction() { + var previousStrict, param, method; + + previousStrict = strict; + strict = true; + param = parseParams(); + method = parsePropertyFunction(param.params); + strict = previousStrict; + + return method; + } + + function parseObjectPropertyKey() { + var token, node = new Node(); + + token = lex(); + + // Note: This function is called only from parseObjectProperty(), where + // EOF and Punctuator tokens are already filtered out. + + if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { + if (strict && token.octal) { + tolerateUnexpectedToken(token, Messages.StrictOctalLiteral); + } + return node.finishLiteral(token); + } + + return node.finishIdentifier(token.value); + } + + function parseObjectProperty() { + var token, key, id, value, param, node = new Node(); + + token = lookahead; + + if (token.type === Token.Identifier) { + + id = parseObjectPropertyKey(); + + // Property Assignment: Getter and Setter. + + if (token.value === 'get' && !(match(':') || match('('))) { + key = parseObjectPropertyKey(); + expect('('); + expect(')'); + value = parsePropertyFunction([]); + return node.finishProperty('get', key, value, false, false); + } + if (token.value === 'set' && !(match(':') || match('('))) { + key = parseObjectPropertyKey(); + expect('('); + token = lookahead; + if (token.type !== Token.Identifier) { + expect(')'); + tolerateUnexpectedToken(token); + value = parsePropertyFunction([]); + } else { + param = [ parseVariableIdentifier() ]; + expect(')'); + value = parsePropertyFunction(param, token); + } + return node.finishProperty('set', key, value, false, false); + } + if (match(':')) { + lex(); + value = parseAssignmentExpression(); + return node.finishProperty('init', id, value, false, false); + } + if (match('(')) { + value = parsePropertyMethodFunction(); + return node.finishProperty('init', id, value, true, false); + } + + value = id; + return node.finishProperty('init', id, value, false, true); + } + if (token.type === Token.EOF || token.type === Token.Punctuator) { + throwUnexpectedToken(token); + } else { + key = parseObjectPropertyKey(); + if (match(':')) { + lex(); + value = parseAssignmentExpression(); + return node.finishProperty('init', key, value, false, false); + } + if (match('(')) { + value = parsePropertyMethodFunction(); + return node.finishProperty('init', key, value, true, false); + } + throwUnexpectedToken(lex()); + } + } + + function parseObjectInitialiser() { + var properties = [], property, name, key, kind, map = {}, toString = String, node = new Node(); + + expect('{'); + + while (!match('}')) { + property = parseObjectProperty(); + + if (property.key.type === Syntax.Identifier) { + name = property.key.name; + } else { + name = toString(property.key.value); + } + kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; + + key = '$' + name; + if (Object.prototype.hasOwnProperty.call(map, key)) { + if (map[key] === PropertyKind.Data) { + if (strict && kind === PropertyKind.Data) { + tolerateError(Messages.StrictDuplicateProperty); + } else if (kind !== PropertyKind.Data) { + tolerateError(Messages.AccessorDataProperty); + } + } else { + if (kind === PropertyKind.Data) { + tolerateError(Messages.AccessorDataProperty); + } else if (map[key] & kind) { + tolerateError(Messages.AccessorGetSet); + } + } + map[key] |= kind; + } else { + map[key] = kind; + } + + properties.push(property); + + if (!match('}')) { + expectCommaSeparator(); + } + } + + expect('}'); + + return node.finishObjectExpression(properties); + } + + // 11.1.6 The Grouping Operator + + function parseGroupExpression() { + var expr; + + expect('('); + + if (match(')')) { + lex(); + return PlaceHolders.ArrowParameterPlaceHolder; + } + + ++state.parenthesisCount; + + expr = parseExpression(); + + expect(')'); + + return expr; + } + + + // 11.1 Primary Expressions + + function parsePrimaryExpression() { + var type, token, expr, node; + + if (match('(')) { + return parseGroupExpression(); + } + + if (match('[')) { + return parseArrayInitialiser(); + } + + if (match('{')) { + return parseObjectInitialiser(); + } + + type = lookahead.type; + node = new Node(); + + if (type === Token.Identifier) { + expr = node.finishIdentifier(lex().value); + } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && lookahead.octal) { + tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral); + } + expr = node.finishLiteral(lex()); + } else if (type === Token.Keyword) { + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + if (matchKeyword('this')) { + lex(); + expr = node.finishThisExpression(); + } else { + throwUnexpectedToken(lex()); + } + } else if (type === Token.BooleanLiteral) { + token = lex(); + token.value = (token.value === 'true'); + expr = node.finishLiteral(token); + } else if (type === Token.NullLiteral) { + token = lex(); + token.value = null; + expr = node.finishLiteral(token); + } else if (match('/') || match('/=')) { + if (typeof extra.tokens !== 'undefined') { + expr = node.finishLiteral(collectRegex()); + } else { + expr = node.finishLiteral(scanRegExp()); + } + peek(); + } else { + throwUnexpectedToken(lex()); + } + + return expr; + } + + // 11.2 Left-Hand-Side Expressions + + function parseArguments() { + var args = []; + + expect('('); + + if (!match(')')) { + while (index < length) { + args.push(parseAssignmentExpression()); + if (match(')')) { + break; + } + expectCommaSeparator(); + } + } + + expect(')'); + + return args; + } + + function parseNonComputedProperty() { + var token, node = new Node(); + + token = lex(); + + if (!isIdentifierName(token)) { + throwUnexpectedToken(token); + } + + return node.finishIdentifier(token.value); + } + + function parseNonComputedMember() { + expect('.'); + + return parseNonComputedProperty(); + } + + function parseComputedMember() { + var expr; + + expect('['); + + expr = parseExpression(); + + expect(']'); + + return expr; + } + + function parseNewExpression() { + var callee, args, node = new Node(); + + expectKeyword('new'); + callee = parseLeftHandSideExpression(); + args = match('(') ? parseArguments() : []; + + return node.finishNewExpression(callee, args); + } + + function parseLeftHandSideExpressionAllowCall() { + var expr, args, property, startToken, previousAllowIn = state.allowIn; + + startToken = lookahead; + state.allowIn = true; + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + for (;;) { + if (match('.')) { + property = parseNonComputedMember(); + expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); + } else if (match('(')) { + args = parseArguments(); + expr = new WrappingNode(startToken).finishCallExpression(expr, args); + } else if (match('[')) { + property = parseComputedMember(); + expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); + } else { + break; + } + } + state.allowIn = previousAllowIn; + + return expr; + } + + function parseLeftHandSideExpression() { + var expr, property, startToken; + assert(state.allowIn, 'callee of new expression always allow in keyword.'); + + startToken = lookahead; + + expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + + for (;;) { + if (match('[')) { + property = parseComputedMember(); + expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); + } else if (match('.')) { + property = parseNonComputedMember(); + expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); + } else { + break; + } + } + return expr; + } + + // 11.3 Postfix Expressions + + function parsePostfixExpression() { + var expr, token, startToken = lookahead; + + expr = parseLeftHandSideExpressionAllowCall(); + + if (lookahead.type === Token.Punctuator) { + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + tolerateError(Messages.StrictLHSPostfix); + } + + if (!isLeftHandSide(expr)) { + tolerateError(Messages.InvalidLHSInAssignment); + } + + token = lex(); + expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr); + } + } + + return expr; + } + + // 11.4 Unary Operators + + function parseUnaryExpression() { + var token, expr, startToken; + + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + expr = parsePostfixExpression(); + } else if (match('++') || match('--')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + // 11.4.4, 11.4.5 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + tolerateError(Messages.StrictLHSPrefix); + } + + if (!isLeftHandSide(expr)) { + tolerateError(Messages.InvalidLHSInAssignment); + } + + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); + } else if (match('+') || match('-') || match('~') || match('!')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); + } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); + if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { + tolerateError(Messages.StrictDelete); + } + } else { + expr = parsePostfixExpression(); + } + + return expr; + } + + function binaryPrecedence(token, allowIn) { + var prec = 0; + + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; + } + + switch (token.value) { + case '||': + prec = 1; + break; + + case '&&': + prec = 2; + break; + + case '|': + prec = 3; + break; + + case '^': + prec = 4; + break; + + case '&': + prec = 5; + break; + + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; + + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; + + case 'in': + prec = allowIn ? 7 : 0; + break; + + case '<<': + case '>>': + case '>>>': + prec = 8; + break; + + case '+': + case '-': + prec = 9; + break; + + case '*': + case '/': + case '%': + prec = 11; + break; + + default: + break; + } + + return prec; + } + + // 11.5 Multiplicative Operators + // 11.6 Additive Operators + // 11.7 Bitwise Shift Operators + // 11.8 Relational Operators + // 11.9 Equality Operators + // 11.10 Binary Bitwise Operators + // 11.11 Binary Logical Operators + + function parseBinaryExpression() { + var marker, markers, expr, token, prec, stack, right, operator, left, i; + + marker = lookahead; + left = parseUnaryExpression(); + if (left === PlaceHolders.ArrowParameterPlaceHolder) { + return left; + } + + token = lookahead; + prec = binaryPrecedence(token, state.allowIn); + if (prec === 0) { + return left; + } + token.prec = prec; + lex(); + + markers = [marker, lookahead]; + right = parseUnaryExpression(); + + stack = [left, token, right]; + + while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { + + // Reduce: make a binary expression from the three topmost entries. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + right = stack.pop(); + operator = stack.pop().value; + left = stack.pop(); + markers.pop(); + expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right); + stack.push(expr); + } + + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + markers.push(lookahead); + expr = parseUnaryExpression(); + stack.push(expr); + } + + // Final reduce to clean-up the stack. + i = stack.length - 1; + expr = stack[i]; + markers.pop(); + while (i > 1) { + expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + i -= 2; + } + + return expr; + } + + + // 11.12 Conditional Operator + + function parseConditionalExpression() { + var expr, previousAllowIn, consequent, alternate, startToken; + + startToken = lookahead; + + expr = parseBinaryExpression(); + if (expr === PlaceHolders.ArrowParameterPlaceHolder) { + return expr; + } + if (match('?')) { + lex(); + previousAllowIn = state.allowIn; + state.allowIn = true; + consequent = parseAssignmentExpression(); + state.allowIn = previousAllowIn; + expect(':'); + alternate = parseAssignmentExpression(); + + expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate); + } + + return expr; + } + + // [ES6] 14.2 Arrow Function + + function parseConciseBody() { + if (match('{')) { + return parseFunctionSourceElements(); + } + return parseAssignmentExpression(); + } + + function reinterpretAsCoverFormalsList(expressions) { + var i, len, param, params, defaults, defaultCount, options, rest, token; + + params = []; + defaults = []; + defaultCount = 0; + rest = null; + options = { + paramSet: {} + }; + + for (i = 0, len = expressions.length; i < len; i += 1) { + param = expressions[i]; + if (param.type === Syntax.Identifier) { + params.push(param); + defaults.push(null); + validateParam(options, param, param.name); + } else if (param.type === Syntax.AssignmentExpression) { + params.push(param.left); + defaults.push(param.right); + ++defaultCount; + validateParam(options, param.left, param.left.name); + } else { + return null; + } + } + + if (options.message === Messages.StrictParamDupe) { + token = strict ? options.stricted : options.firstRestricted; + throwUnexpectedToken(token, options.message); + } + + if (defaultCount === 0) { + defaults = []; + } + + return { + params: params, + defaults: defaults, + rest: rest, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; + } + + function parseArrowFunctionExpression(options, node) { + var previousStrict, body; + + expect('=>'); + previousStrict = strict; + + body = parseConciseBody(); + + if (strict && options.firstRestricted) { + throwUnexpectedToken(options.firstRestricted, options.message); + } + if (strict && options.stricted) { + tolerateUnexpectedToken(options.stricted, options.message); + } + + strict = previousStrict; + + return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement); + } + + // 11.13 Assignment Operators + + function parseAssignmentExpression() { + var oldParenthesisCount, token, expr, right, list, startToken; + + oldParenthesisCount = state.parenthesisCount; + + startToken = lookahead; + token = lookahead; + + expr = parseConditionalExpression(); + + if (expr === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) { + if (state.parenthesisCount === oldParenthesisCount || + state.parenthesisCount === (oldParenthesisCount + 1)) { + if (expr.type === Syntax.Identifier) { + list = reinterpretAsCoverFormalsList([ expr ]); + } else if (expr.type === Syntax.AssignmentExpression) { + list = reinterpretAsCoverFormalsList([ expr ]); + } else if (expr.type === Syntax.SequenceExpression) { + list = reinterpretAsCoverFormalsList(expr.expressions); + } else if (expr === PlaceHolders.ArrowParameterPlaceHolder) { + list = reinterpretAsCoverFormalsList([]); + } + if (list) { + return parseArrowFunctionExpression(list, new WrappingNode(startToken)); + } + } + } + + if (matchAssign()) { + // LeftHandSideExpression + if (!isLeftHandSide(expr)) { + tolerateError(Messages.InvalidLHSInAssignment); + } + + // 11.13.1 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + tolerateUnexpectedToken(token, Messages.StrictLHSAssignment); + } + + token = lex(); + right = parseAssignmentExpression(); + expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right); + } + + return expr; + } + + // 11.14 Comma Operator + + function parseExpression() { + var expr, startToken = lookahead, expressions; + + expr = parseAssignmentExpression(); + + if (match(',')) { + expressions = [expr]; + + while (index < length) { + if (!match(',')) { + break; + } + lex(); + expressions.push(parseAssignmentExpression()); + } + + expr = new WrappingNode(startToken).finishSequenceExpression(expressions); + } + + return expr; + } + + // 12.1 Block + + function parseStatementList() { + var list = [], + statement; + + while (index < length) { + if (match('}')) { + break; + } + statement = parseSourceElement(); + if (typeof statement === 'undefined') { + break; + } + list.push(statement); + } + + return list; + } + + function parseBlock() { + var block, node = new Node(); + + expect('{'); + + block = parseStatementList(); + + expect('}'); + + return node.finishBlockStatement(block); + } + + // 12.2 Variable Statement + + function parseVariableIdentifier() { + var token, node = new Node(); + + token = lex(); + + if (token.type !== Token.Identifier) { + if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) { + tolerateUnexpectedToken(token, Messages.StrictReservedWord); + } else { + throwUnexpectedToken(token); + } + } + + return node.finishIdentifier(token.value); + } + + function parseVariableDeclaration(kind) { + var init = null, id, node = new Node(); + + id = parseVariableIdentifier(); + + // 12.2.1 + if (strict && isRestrictedWord(id.name)) { + tolerateError(Messages.StrictVarName); + } + + if (kind === 'const') { + expect('='); + init = parseAssignmentExpression(); + } else if (match('=')) { + lex(); + init = parseAssignmentExpression(); + } + + return node.finishVariableDeclarator(id, init); + } + + function parseVariableDeclarationList(kind) { + var list = []; + + do { + list.push(parseVariableDeclaration(kind)); + if (!match(',')) { + break; + } + lex(); + } while (index < length); + + return list; + } + + function parseVariableStatement(node) { + var declarations; + + expectKeyword('var'); + + declarations = parseVariableDeclarationList(); + + consumeSemicolon(); + + return node.finishVariableDeclaration(declarations, 'var'); + } + + // kind may be `const` or `let` + // Both are experimental and not in the specification yet. + // see http://wiki.ecmascript.org/doku.php?id=harmony:const + // and http://wiki.ecmascript.org/doku.php?id=harmony:let + function parseConstLetDeclaration(kind) { + var declarations, node = new Node(); + + expectKeyword(kind); + + declarations = parseVariableDeclarationList(kind); + + consumeSemicolon(); + + return node.finishVariableDeclaration(declarations, kind); + } + + // 12.3 Empty Statement + + function parseEmptyStatement() { + var node = new Node(); + expect(';'); + return node.finishEmptyStatement(); + } + + // 12.4 Expression Statement + + function parseExpressionStatement(node) { + var expr = parseExpression(); + consumeSemicolon(); + return node.finishExpressionStatement(expr); + } + + // 12.5 If statement + + function parseIfStatement(node) { + var test, consequent, alternate; + + expectKeyword('if'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + consequent = parseStatement(); + + if (matchKeyword('else')) { + lex(); + alternate = parseStatement(); + } else { + alternate = null; + } + + return node.finishIfStatement(test, consequent, alternate); + } + + // 12.6 Iteration Statements + + function parseDoWhileStatement(node) { + var body, test, oldInIteration; + + expectKeyword('do'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + if (match(';')) { + lex(); + } + + return node.finishDoWhileStatement(body, test); + } + + function parseWhileStatement(node) { + var test, body, oldInIteration; + + expectKeyword('while'); + + expect('('); + + test = parseExpression(); + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return node.finishWhileStatement(test, body); + } + + function parseForVariableDeclaration() { + var token, declarations, node = new Node(); + + token = lex(); + declarations = parseVariableDeclarationList(); + + return node.finishVariableDeclaration(declarations, token.value); + } + + function parseForStatement(node) { + var init, test, update, left, right, body, oldInIteration, previousAllowIn = state.allowIn; + + init = test = update = null; + + expectKeyword('for'); + + expect('('); + + if (match(';')) { + lex(); + } else { + if (matchKeyword('var') || matchKeyword('let')) { + state.allowIn = false; + init = parseForVariableDeclaration(); + state.allowIn = previousAllowIn; + + if (init.declarations.length === 1 && matchKeyword('in')) { + lex(); + left = init; + right = parseExpression(); + init = null; + } + } else { + state.allowIn = false; + init = parseExpression(); + state.allowIn = previousAllowIn; + + if (matchKeyword('in')) { + // LeftHandSideExpression + if (!isLeftHandSide(init)) { + tolerateError(Messages.InvalidLHSInForIn); + } + + lex(); + left = init; + right = parseExpression(); + init = null; + } + } + + if (typeof left === 'undefined') { + expect(';'); + } + } + + if (typeof left === 'undefined') { + + if (!match(';')) { + test = parseExpression(); + } + expect(';'); + + if (!match(')')) { + update = parseExpression(); + } + } + + expect(')'); + + oldInIteration = state.inIteration; + state.inIteration = true; + + body = parseStatement(); + + state.inIteration = oldInIteration; + + return (typeof left === 'undefined') ? + node.finishForStatement(init, test, update, body) : + node.finishForInStatement(left, right, body); + } + + // 12.7 The continue statement + + function parseContinueStatement(node) { + var label = null, key; + + expectKeyword('continue'); + + // Optimize the most common form: 'continue;'. + if (source.charCodeAt(index) === 0x3B) { + lex(); + + if (!state.inIteration) { + throwError(Messages.IllegalContinue); + } + + return node.finishContinueStatement(null); + } + + if (peekLineTerminator()) { + if (!state.inIteration) { + throwError(Messages.IllegalContinue); + } + + return node.finishContinueStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError(Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !state.inIteration) { + throwError(Messages.IllegalContinue); + } + + return node.finishContinueStatement(label); + } + + // 12.8 The break statement + + function parseBreakStatement(node) { + var label = null, key; + + expectKeyword('break'); + + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(index) === 0x3B) { + lex(); + + if (!(state.inIteration || state.inSwitch)) { + throwError(Messages.IllegalBreak); + } + + return node.finishBreakStatement(null); + } + + if (peekLineTerminator()) { + if (!(state.inIteration || state.inSwitch)) { + throwError(Messages.IllegalBreak); + } + + return node.finishBreakStatement(null); + } + + if (lookahead.type === Token.Identifier) { + label = parseVariableIdentifier(); + + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError(Messages.UnknownLabel, label.name); + } + } + + consumeSemicolon(); + + if (label === null && !(state.inIteration || state.inSwitch)) { + throwError(Messages.IllegalBreak); + } + + return node.finishBreakStatement(label); + } + + // 12.9 The return statement + + function parseReturnStatement(node) { + var argument = null; + + expectKeyword('return'); + + if (!state.inFunctionBody) { + tolerateError(Messages.IllegalReturn); + } + + // 'return' followed by a space and an identifier is very common. + if (source.charCodeAt(index) === 0x20) { + if (isIdentifierStart(source.charCodeAt(index + 1))) { + argument = parseExpression(); + consumeSemicolon(); + return node.finishReturnStatement(argument); + } + } + + if (peekLineTerminator()) { + return node.finishReturnStatement(null); + } + + if (!match(';')) { + if (!match('}') && lookahead.type !== Token.EOF) { + argument = parseExpression(); + } + } + + consumeSemicolon(); + + return node.finishReturnStatement(argument); + } + + // 12.10 The with statement + + function parseWithStatement(node) { + var object, body; + + if (strict) { + // TODO(ikarienator): Should we update the test cases instead? + skipComment(); + tolerateError(Messages.StrictModeWith); + } + + expectKeyword('with'); + + expect('('); + + object = parseExpression(); + + expect(')'); + + body = parseStatement(); + + return node.finishWithStatement(object, body); + } + + // 12.10 The swith statement + + function parseSwitchCase() { + var test, consequent = [], statement, node = new Node(); + + if (matchKeyword('default')) { + lex(); + test = null; + } else { + expectKeyword('case'); + test = parseExpression(); + } + expect(':'); + + while (index < length) { + if (match('}') || matchKeyword('default') || matchKeyword('case')) { + break; + } + statement = parseStatement(); + consequent.push(statement); + } + + return node.finishSwitchCase(test, consequent); + } + + function parseSwitchStatement(node) { + var discriminant, cases, clause, oldInSwitch, defaultFound; + + expectKeyword('switch'); + + expect('('); + + discriminant = parseExpression(); + + expect(')'); + + expect('{'); + + cases = []; + + if (match('}')) { + lex(); + return node.finishSwitchStatement(discriminant, cases); + } + + oldInSwitch = state.inSwitch; + state.inSwitch = true; + defaultFound = false; + + while (index < length) { + if (match('}')) { + break; + } + clause = parseSwitchCase(); + if (clause.test === null) { + if (defaultFound) { + throwError(Messages.MultipleDefaultsInSwitch); + } + defaultFound = true; + } + cases.push(clause); + } + + state.inSwitch = oldInSwitch; + + expect('}'); + + return node.finishSwitchStatement(discriminant, cases); + } + + // 12.13 The throw statement + + function parseThrowStatement(node) { + var argument; + + expectKeyword('throw'); + + if (peekLineTerminator()) { + throwError(Messages.NewlineAfterThrow); + } + + argument = parseExpression(); + + consumeSemicolon(); + + return node.finishThrowStatement(argument); + } + + // 12.14 The try statement + + function parseCatchClause() { + var param, body, node = new Node(); + + expectKeyword('catch'); + + expect('('); + if (match(')')) { + throwUnexpectedToken(lookahead); + } + + param = parseVariableIdentifier(); + // 12.14.1 + if (strict && isRestrictedWord(param.name)) { + tolerateError(Messages.StrictCatchVariable); + } + + expect(')'); + body = parseBlock(); + return node.finishCatchClause(param, body); + } + + function parseTryStatement(node) { + var block, handlers = [], finalizer = null; + + expectKeyword('try'); + + block = parseBlock(); + + if (matchKeyword('catch')) { + handlers.push(parseCatchClause()); + } + + if (matchKeyword('finally')) { + lex(); + finalizer = parseBlock(); + } + + if (handlers.length === 0 && !finalizer) { + throwError(Messages.NoCatchOrFinally); + } + + return node.finishTryStatement(block, [], handlers, finalizer); + } + + // 12.15 The debugger statement + + function parseDebuggerStatement(node) { + expectKeyword('debugger'); + + consumeSemicolon(); + + return node.finishDebuggerStatement(); + } + + // 12 Statements + + function parseStatement() { + var type = lookahead.type, + expr, + labeledBody, + key, + node; + + if (type === Token.EOF) { + throwUnexpectedToken(lookahead); + } + + if (type === Token.Punctuator && lookahead.value === '{') { + return parseBlock(); + } + + node = new Node(); + + if (type === Token.Punctuator) { + switch (lookahead.value) { + case ';': + return parseEmptyStatement(node); + case '(': + return parseExpressionStatement(node); + default: + break; + } + } else if (type === Token.Keyword) { + switch (lookahead.value) { + case 'break': + return parseBreakStatement(node); + case 'continue': + return parseContinueStatement(node); + case 'debugger': + return parseDebuggerStatement(node); + case 'do': + return parseDoWhileStatement(node); + case 'for': + return parseForStatement(node); + case 'function': + return parseFunctionDeclaration(node); + case 'if': + return parseIfStatement(node); + case 'return': + return parseReturnStatement(node); + case 'switch': + return parseSwitchStatement(node); + case 'throw': + return parseThrowStatement(node); + case 'try': + return parseTryStatement(node); + case 'var': + return parseVariableStatement(node); + case 'while': + return parseWhileStatement(node); + case 'with': + return parseWithStatement(node); + default: + break; + } + } + + expr = parseExpression(); + + // 12.12 Labelled Statements + if ((expr.type === Syntax.Identifier) && match(':')) { + lex(); + + key = '$' + expr.name; + if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { + throwError(Messages.Redeclaration, 'Label', expr.name); + } + + state.labelSet[key] = true; + labeledBody = parseStatement(); + delete state.labelSet[key]; + return node.finishLabeledStatement(expr, labeledBody); + } + + consumeSemicolon(); + + return node.finishExpressionStatement(expr); + } + + // 13 Function Definition + + function parseFunctionSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted, + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesisCount, + node = new Node(); + + expect('{'); + + while (index < length) { + if (lookahead.type !== Token.StringLiteral) { + break; + } + token = lookahead; + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.start + 1, token.end - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + oldLabelSet = state.labelSet; + oldInIteration = state.inIteration; + oldInSwitch = state.inSwitch; + oldInFunctionBody = state.inFunctionBody; + oldParenthesisCount = state.parenthesizedCount; + + state.labelSet = {}; + state.inIteration = false; + state.inSwitch = false; + state.inFunctionBody = true; + state.parenthesizedCount = 0; + + while (index < length) { + if (match('}')) { + break; + } + sourceElement = parseSourceElement(); + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + + expect('}'); + + state.labelSet = oldLabelSet; + state.inIteration = oldInIteration; + state.inSwitch = oldInSwitch; + state.inFunctionBody = oldInFunctionBody; + state.parenthesizedCount = oldParenthesisCount; + + return node.finishBlockStatement(sourceElements); + } + + function validateParam(options, param, name) { + var key = '$' + name; + if (strict) { + if (isRestrictedWord(name)) { + options.stricted = param; + options.message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.stricted = param; + options.message = Messages.StrictParamDupe; + } + } else if (!options.firstRestricted) { + if (isRestrictedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.firstRestricted = param; + options.message = Messages.StrictParamDupe; + } + } + options.paramSet[key] = true; + } + + function parseParam(options) { + var token, param, def; + + token = lookahead; + param = parseVariableIdentifier(); + validateParam(options, token, token.value); + if (match('=')) { + lex(); + def = parseAssignmentExpression(); + ++options.defaultCount; + } + + options.params.push(param); + options.defaults.push(def); + + return !match(')'); + } + + function parseParams(firstRestricted) { + var options; + + options = { + params: [], + defaultCount: 0, + defaults: [], + firstRestricted: firstRestricted + }; + + expect('('); + + if (!match(')')) { + options.paramSet = {}; + while (index < length) { + if (!parseParam(options)) { + break; + } + expect(','); + } + } + + expect(')'); + + if (options.defaultCount === 0) { + options.defaults = []; + } + + return { + params: options.params, + defaults: options.defaults, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; + } + + function parseFunctionDeclaration() { + var id, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, node = new Node(); + + expectKeyword('function'); + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + tolerateUnexpectedToken(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + defaults = tmp.defaults; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwUnexpectedToken(firstRestricted, message); + } + if (strict && stricted) { + tolerateUnexpectedToken(stricted, message); + } + strict = previousStrict; + + return node.finishFunctionDeclaration(id, params, defaults, body); + } + + function parseFunctionExpression() { + var token, id = null, stricted, firstRestricted, message, tmp, + params = [], defaults = [], body, previousStrict, node = new Node(); + + expectKeyword('function'); + + if (!match('(')) { + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + tolerateUnexpectedToken(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + defaults = tmp.defaults; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + + previousStrict = strict; + body = parseFunctionSourceElements(); + if (strict && firstRestricted) { + throwUnexpectedToken(firstRestricted, message); + } + if (strict && stricted) { + tolerateUnexpectedToken(stricted, message); + } + strict = previousStrict; + + return node.finishFunctionExpression(id, params, defaults, body); + } + + // 14 Program + + function parseSourceElement() { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { + case 'const': + case 'let': + return parseConstLetDeclaration(lookahead.value); + case 'function': + return parseFunctionDeclaration(); + default: + return parseStatement(); + } + } + + if (lookahead.type !== Token.EOF) { + return parseStatement(); + } + } + + function parseSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted; + + while (index < length) { + token = lookahead; + if (token.type !== Token.StringLiteral) { + break; + } + + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.start + 1, token.end - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; + } + } + } + + while (index < length) { + sourceElement = parseSourceElement(); + /* istanbul ignore if */ + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + return sourceElements; + } + + function parseProgram() { + var body, node; + + skipComment(); + peek(); + node = new Node(); + strict = false; + + body = parseSourceElements(); + return node.finishProgram(body); + } + + function filterTokenLocation() { + var i, entry, token, tokens = []; + + for (i = 0; i < extra.tokens.length; ++i) { + entry = extra.tokens[i]; + token = { + type: entry.type, + value: entry.value + }; + if (entry.regex) { + token.regex = { + pattern: entry.regex.pattern, + flags: entry.regex.flags + }; + } + if (extra.range) { + token.range = entry.range; + } + if (extra.loc) { + token.loc = entry.loc; + } + tokens.push(token); + } + + extra.tokens = tokens; + } + + function tokenize(code, options) { + var toString, + tokens; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + lastCommentStart: -1 + }; + + extra = {}; + + // Options matching. + options = options || {}; + + // Of course we collect tokens here. + options.tokens = true; + extra.tokens = []; + extra.tokenize = true; + // The following two fields are necessary to compute the Regex tokens. + extra.openParenToken = -1; + extra.openCurlyToken = -1; + + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + + try { + peek(); + if (lookahead.type === Token.EOF) { + return extra.tokens; + } + + lex(); + while (lookahead.type !== Token.EOF) { + try { + lex(); + } catch (lexError) { + if (extra.errors) { + extra.errors.push(lexError); + // We have to break on the first error + // to avoid infinite loops. + break; + } else { + throw lexError; + } + } + } + + filterTokenLocation(); + tokens = extra.tokens; + if (typeof extra.comments !== 'undefined') { + tokens.comments = extra.comments; + } + if (typeof extra.errors !== 'undefined') { + tokens.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + extra = {}; + } + return tokens; + } + + function parse(code, options) { + var program, toString; + + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } + + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + parenthesisCount: 0, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + lastCommentStart: -1 + }; + + extra = {}; + if (typeof options !== 'undefined') { + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; + extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; + + if (extra.loc && options.source !== null && options.source !== undefined) { + extra.source = toString(options.source); + } + + if (typeof options.tokens === 'boolean' && options.tokens) { + extra.tokens = []; + } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; + } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; + } + if (extra.attachComment) { + extra.range = true; + extra.comments = []; + extra.bottomRightStack = []; + extra.trailingComments = []; + extra.leadingComments = []; + } + } + + try { + program = parseProgram(); + if (typeof extra.comments !== 'undefined') { + program.comments = extra.comments; + } + if (typeof extra.tokens !== 'undefined') { + filterTokenLocation(); + program.tokens = extra.tokens; + } + if (typeof extra.errors !== 'undefined') { + program.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + extra = {}; + } + + return program; + } + + // Sync with *.json manifests. + exports.version = '2.0.0'; + + exports.tokenize = tokenize; + + exports.parse = parse; + + // Deep copy. + /* istanbul ignore next */ + exports.Syntax = (function () { + var name, types = {}; + + if (typeof Object.create === 'function') { + types = Object.create(null); + } + + for (name in Syntax) { + if (Syntax.hasOwnProperty(name)) { + types[name] = Syntax[name]; + } + } + + if (typeof Object.freeze === 'function') { + Object.freeze(types); + } + + return types; + }()); + +})); +/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/editor/js/libs/sortable.min.js b/editor/js/libs/sortable.min.js new file mode 100644 index 00000000000000..56d114ba9679be --- /dev/null +++ b/editor/js/libs/sortable.min.js @@ -0,0 +1,2 @@ +/*! Sortable 1.0.1 - MIT | git://github.com/rubaxa/Sortable.git */ +!function(a){"use strict";"function"==typeof define&&define.amd?define(a):"undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports=a():"undefined"!=typeof Package?Sortable=a():window.Sortable=a()}(function(){"use strict";function a(a,b){this.el=a,this.options=b=b||{};var d={group:Math.random(),sort:!0,disabled:!1,store:null,handle:null,scroll:!0,scrollSensitivity:30,scrollSpeed:10,draggable:/[uo]l/i.test(a.nodeName)?"li":">*",ghostClass:"sortable-ghost",ignore:"a, img",filter:null,animation:0,setData:function(a,b){a.setData("Text",b.textContent)},dropBubble:!1,dragoverBubble:!1};for(var e in d)!(e in b)&&(b[e]=d[e]);var g=b.group;g&&"object"==typeof g||(g=b.group={name:g}),["pull","put"].forEach(function(a){a in g||(g[a]=!0)}),L.forEach(function(d){b[d]=c(this,b[d]||M),f(a,d.substr(2).toLowerCase(),b[d])},this),a[E]=g.name+" "+(g.put.join?g.put.join(" "):"");for(var h in this)"_"===h.charAt(0)&&(this[h]=c(this,this[h]));f(a,"mousedown",this._onTapStart),f(a,"touchstart",this._onTapStart),I&&f(a,"selectstart",this._onTapStart),f(a,"dragover",this._onDragOver),f(a,"dragenter",this._onDragOver),P.push(this._onDragOver),b.store&&this.sort(b.store.get(this))}function b(a){s&&s.state!==a&&(i(s,"display",a?"none":""),!a&&s.state&&t.insertBefore(s,q),s.state=a)}function c(a,b){var c=O.call(arguments,2);return b.bind?b.bind.apply(b,[a].concat(c)):function(){return b.apply(a,c.concat(O.call(arguments)))}}function d(a,b,c){if(a){c=c||G,b=b.split(".");var d=b.shift().toUpperCase(),e=new RegExp("\\s("+b.join("|")+")\\s","g");do if(">*"===d&&a.parentNode===c||(""===d||a.nodeName.toUpperCase()==d)&&(!b.length||((" "+a.className+" ").match(e)||[]).length==b.length))return a;while(a!==c&&(a=a.parentNode))}return null}function e(a){a.dataTransfer.dropEffect="move",a.preventDefault()}function f(a,b,c){a.addEventListener(b,c,!1)}function g(a,b,c){a.removeEventListener(b,c,!1)}function h(a,b,c){if(a)if(a.classList)a.classList[c?"add":"remove"](b);else{var d=(" "+a.className+" ").replace(/\s+/g," ").replace(" "+b+" ","");a.className=d+(c?" "+b:"")}}function i(a,b,c){var d=a&&a.style;if(d){if(void 0===c)return G.defaultView&&G.defaultView.getComputedStyle?c=G.defaultView.getComputedStyle(a,""):a.currentStyle&&(c=a.currentStyle),void 0===b?c:c[b];b in d||(b="-webkit-"+b),d[b]=c+("string"==typeof c?"":"px")}}function j(a,b,c){if(a){var d=a.getElementsByTagName(b),e=0,f=d.length;if(c)for(;f>e;e++)c(d[e],e);return d}return[]}function k(a){a.draggable=!1}function l(){J=!1}function m(a,b){var c=a.lastElementChild,d=c.getBoundingClientRect();return b.clientY-(d.top+d.height)>5&&c}function n(a){for(var b=a.tagName+a.className+a.src+a.href+a.textContent,c=b.length,d=0;c--;)d+=b.charCodeAt(c);return d.toString(36)}function o(a){for(var b=0;a&&(a=a.previousElementSibling)&&"TEMPLATE"!==a.nodeName.toUpperCase();)b++;return b}function p(a,b){var c,d;return function(){void 0===c&&(c=arguments,d=this,setTimeout(function(){1===c.length?a.call(d,c[0]):a.apply(d,c),c=void 0},b))}}var q,r,s,t,u,v,w,x,y,z,A,B,C,D={},E="Sortable"+(new Date).getTime(),F=window,G=F.document,H=F.parseInt,I=!!G.createElement("div").dragDrop,J=!1,K=function(a,b,c,d,e,f){var g=G.createEvent("Event");g.initEvent(b,!0,!0),g.item=c||a,g.from=d||a,g.clone=s,g.oldIndex=e,g.newIndex=f,a.dispatchEvent(g)},L="onAdd onUpdate onRemove onStart onEnd onFilter onSort".split(" "),M=function(){},N=Math.abs,O=[].slice,P=[];return a.prototype={constructor:a,_dragStarted:function(){h(q,this.options.ghostClass,!0),a.active=this,K(t,"start",q,t,y)},_onTapStart:function(a){var b=a.type,c=a.touches&&a.touches[0],e=(c||a).target,g=e,h=this.options,i=this.el,l=h.filter;if(!("mousedown"===b&&0!==a.button||h.disabled)){if(h.handle&&(e=d(e,h.handle,i)),e=d(e,h.draggable,i),y=o(e),"function"==typeof l){if(l.call(this,a,e,this))return K(g,"filter",e,i,y),void a.preventDefault()}else if(l&&(l=l.split(",").some(function(a){return a=d(g,a.trim(),i),a?(K(a,"filter",e,i,y),!0):void 0})))return void a.preventDefault();if(e&&!q&&e.parentNode===i){"selectstart"===b&&e.dragDrop(),B=a,t=this.el,q=e,v=q.nextSibling,A=this.options.group,q.draggable=!0,h.ignore.split(",").forEach(function(a){j(e,a.trim(),k)}),c&&(B={target:e,clientX:c.clientX,clientY:c.clientY},this._onDragStart(B,!0),a.preventDefault()),f(G,"mouseup",this._onDrop),f(G,"touchend",this._onDrop),f(G,"touchcancel",this._onDrop),f(q,"dragend",this),f(t,"dragstart",this._onDragStart),f(G,"dragover",this);try{G.selection?G.selection.empty():window.getSelection().removeAllRanges()}catch(m){}}}},_emulateDragOver:function(){if(C){i(r,"display","none");var a=G.elementFromPoint(C.clientX,C.clientY),b=a,c=this.options.group.name,d=P.length;if(b)do{if((" "+b[E]+" ").indexOf(c)>-1){for(;d--;)P[d]({clientX:C.clientX,clientY:C.clientY,target:a,rootEl:b});break}a=b}while(b=b.parentNode);i(r,"display","")}},_onTouchMove:function(a){if(B){var b=a.touches[0],c=b.clientX-B.clientX,d=b.clientY-B.clientY,e="translate3d("+c+"px,"+d+"px,0)";C=b,i(r,"webkitTransform",e),i(r,"mozTransform",e),i(r,"msTransform",e),i(r,"transform",e),this._onDrag(b),a.preventDefault()}},_onDragStart:function(a,b){var c=a.dataTransfer,d=this.options;if(this._offUpEvents(),"clone"==A.pull&&(s=q.cloneNode(!0),i(s,"display","none"),t.insertBefore(s,q)),b){var e,g=q.getBoundingClientRect(),h=i(q);r=q.cloneNode(!0),i(r,"top",g.top-H(h.marginTop,10)),i(r,"left",g.left-H(h.marginLeft,10)),i(r,"width",g.width),i(r,"height",g.height),i(r,"opacity","0.8"),i(r,"position","fixed"),i(r,"zIndex","100000"),t.appendChild(r),e=r.getBoundingClientRect(),i(r,"width",2*g.width-e.width),i(r,"height",2*g.height-e.height),f(G,"touchmove",this._onTouchMove),f(G,"touchend",this._onDrop),f(G,"touchcancel",this._onDrop),this._loopId=setInterval(this._emulateDragOver,150)}else c&&(c.effectAllowed="move",d.setData&&d.setData.call(this,c,q)),f(G,"drop",this);if(u=d.scroll,u===!0){u=t;do if(u.offsetWidth=i-g)-(e>=g),l=(e>=j-h)-(e>=h);k||l?b=F:u&&(b=u,c=u.getBoundingClientRect(),k=(N(c.right-g)<=e)-(N(c.left-g)<=e),l=(N(c.bottom-h)<=e)-(N(c.top-h)<=e)),(D.vx!==k||D.vy!==l||D.el!==b)&&(D.el=b,D.vx=k,D.vy=l,clearInterval(D.pid),b&&(D.pid=setInterval(function(){b===F?F.scrollTo(F.scrollX+k*f,F.scrollY+l*f):(l&&(b.scrollTop+=l*f),k&&(b.scrollLeft+=k*f))},24)))}},30),_onDragOver:function(a){var c,e,f,g=this.el,h=this.options,j=h.group,k=j.put,n=A===j,o=h.sort;if(void 0!==a.preventDefault&&(a.preventDefault(),!h.dragoverBubble&&a.stopPropagation()),!J&&A&&(n?o||(f=!t.contains(q)):A.pull&&k&&(A.name===j.name||k.indexOf&&~k.indexOf(A.name)))&&(void 0===a.rootEl||a.rootEl===this.el)){if(c=d(a.target,h.draggable,g),e=q.getBoundingClientRect(),f)return b(!0),void(s||v?t.insertBefore(q,s||v):o||t.appendChild(q));if(0===g.children.length||g.children[0]===r||g===a.target&&(c=m(g,a))){if(c){if(c.animated)return;u=c.getBoundingClientRect()}b(n),g.appendChild(q),this._animate(e,q),c&&this._animate(u,c)}else if(c&&!c.animated&&c!==q&&void 0!==c.parentNode[E]){w!==c&&(w=c,x=i(c));var p,u=c.getBoundingClientRect(),y=u.right-u.left,z=u.bottom-u.top,B=/left|right|inline/.test(x.cssFloat+x.display),C=c.offsetWidth>q.offsetWidth,D=c.offsetHeight>q.offsetHeight,F=(B?(a.clientX-u.left)/y:(a.clientY-u.top)/z)>.5,G=c.nextElementSibling;J=!0,setTimeout(l,30),b(n),p=B?c.previousElementSibling===q&&!C||F&&C:G!==q&&!D||F&&D,p&&!G?g.appendChild(q):c.parentNode.insertBefore(q,p?G:c),this._animate(e,q),this._animate(u,c)}}},_animate:function(a,b){var c=this.options.animation;if(c){var d=b.getBoundingClientRect();i(b,"transition","none"),i(b,"transform","translate3d("+(a.left-d.left)+"px,"+(a.top-d.top)+"px,0)"),b.offsetWidth,i(b,"transition","all "+c+"ms"),i(b,"transform","translate3d(0,0,0)"),clearTimeout(b.animated),b.animated=setTimeout(function(){i(b,"transition",""),b.animated=!1},c)}},_offUpEvents:function(){g(G,"mouseup",this._onDrop),g(G,"touchmove",this._onTouchMove),g(G,"touchend",this._onDrop),g(G,"touchcancel",this._onDrop)},_onDrop:function(b){var c=this.el,d=this.options;clearInterval(this._loopId),clearInterval(D.pid),g(G,"drop",this),g(G,"dragover",this),g(c,"dragstart",this._onDragStart),this._offUpEvents(),b&&(b.preventDefault(),!d.dropBubble&&b.stopPropagation(),r&&r.parentNode.removeChild(r),q&&(g(q,"dragend",this),k(q),h(q,this.options.ghostClass,!1),t!==q.parentNode?(z=o(q),K(q.parentNode,"sort",q,t,y,z),K(t,"sort",q,t,y,z),K(q,"add",q,t,y,z),K(t,"remove",q,t,y,z)):(s&&s.parentNode.removeChild(s),q.nextSibling!==v&&(z=o(q),K(t,"update",q,t,y,z),K(t,"sort",q,t,y,z))),a.active&&K(t,"end",q,t,y,z)),t=q=r=v=s=B=C=w=x=A=a.active=null,this.save())},handleEvent:function(a){var b=a.type;"dragover"===b?(this._onDrag(a),e(a)):("drop"===b||"dragend"===b)&&this._onDrop(a)},toArray:function(){for(var a,b=[],c=this.el.children,e=0,f=c.length;f>e;e++)a=c[e],d(a,this.options.draggable,this.el)&&b.push(a.getAttribute("data-id")||n(a));return b},sort:function(a){var b={},c=this.el;this.toArray().forEach(function(a,e){var f=c.children[e];d(f,this.options.draggable,c)&&(b[a]=f)},this),a.forEach(function(a){b[a]&&(c.removeChild(b[a]),c.appendChild(b[a]))})},save:function(){var a=this.options.store;a&&a.set(this)},closest:function(a,b){return d(a,b||this.options.draggable,this.el)},option:function(a,b){var c=this.options;return void 0===b?c[a]:void(c[a]=b)},destroy:function(){var a=this.el,b=this.options;L.forEach(function(c){g(a,c.substr(2).toLowerCase(),b[c])}),g(a,"mousedown",this._onTapStart),g(a,"touchstart",this._onTapStart),g(a,"selectstart",this._onTapStart),g(a,"dragover",this._onDragOver),g(a,"dragenter",this._onDragOver),Array.prototype.forEach.call(a.querySelectorAll("[draggable]"),function(a){a.removeAttribute("draggable")}),P.splice(P.indexOf(this._onDragOver),1),this._onDrop(),this.el=null}},a.utils={on:f,off:g,css:i,find:j,bind:c,is:function(a,b){return!!d(a,b,a)},throttle:p,closest:d,toggleClass:h,dispatchEvent:K,index:o},a.version="1.0.1",a.create=function(b,c){return new a(b,c)},a}); \ No newline at end of file diff --git a/editor/js/libs/ui.js b/editor/js/libs/ui.js index 3221ed641e27b3..2e6637969c684c 100644 --- a/editor/js/libs/ui.js +++ b/editor/js/libs/ui.js @@ -15,7 +15,7 @@ UI.Element.prototype = { setId: function ( id ) { this.dom.id = id; - + return this; }, @@ -137,7 +137,7 @@ UI.Panel.prototype.add = function () { UI.Panel.prototype.remove = function () { for ( var i = 0; i < arguments.length; i ++ ) { - + var argument = arguments[ i ]; if ( argument instanceof UI.Element ) { @@ -503,159 +503,6 @@ UI.Select.prototype.setValue = function ( value ) { }; -// FancySelect - -UI.FancySelect = function () { - - UI.Element.call( this ); - - var scope = this; - - var dom = document.createElement( 'div' ); - dom.className = 'FancySelect'; - dom.tabIndex = 0; // keyup event is ignored without setting tabIndex - - // Broadcast for object selection after arrow navigation - var changeEvent = document.createEvent('HTMLEvents'); - changeEvent.initEvent( 'change', true, true ); - - // Prevent native scroll behavior - dom.addEventListener( 'keydown', function (event) { - - switch ( event.keyCode ) { - case 38: // up - case 40: // down - event.preventDefault(); - event.stopPropagation(); - break; - } - - }, false); - - // Keybindings to support arrow navigation - dom.addEventListener( 'keyup', function (event) { - - switch ( event.keyCode ) { - case 38: // up - case 40: // down - scope.selectedIndex += ( event.keyCode == 38 ) ? -1 : 1; - - if ( scope.selectedIndex >= 0 && scope.selectedIndex < scope.options.length ) { - - // Highlight selected dom elem and scroll parent if needed - scope.setValue( scope.options[ scope.selectedIndex ].value ); - - scope.dom.dispatchEvent( changeEvent ); - - } - - break; - } - - }, false); - - this.dom = dom; - - this.options = []; - this.selectedIndex = -1; - this.selectedValue = null; - - return this; - -}; - -UI.FancySelect.prototype = Object.create( UI.Element.prototype ); -UI.FancySelect.prototype.constructor = UI.FancySelect; - -UI.FancySelect.prototype.setOptions = function ( options ) { - - var scope = this; - - var changeEvent = document.createEvent( 'HTMLEvents' ); - changeEvent.initEvent( 'change', true, true ); - - while ( scope.dom.children.length > 0 ) { - - scope.dom.removeChild( scope.dom.firstChild ); - - } - - scope.options = []; - - for ( var i = 0; i < options.length; i ++ ) { - - var option = options[ i ]; - - var div = document.createElement( 'div' ); - div.className = 'option'; - div.innerHTML = option.html; - div.value = option.value; - scope.dom.appendChild( div ); - - scope.options.push( div ); - - div.addEventListener( 'click', function ( event ) { - - scope.setValue( this.value ); - scope.dom.dispatchEvent( changeEvent ); - - }, false ); - - } - - return scope; - -}; - -UI.FancySelect.prototype.getValue = function () { - - return this.selectedValue; - -}; - -UI.FancySelect.prototype.setValue = function ( value ) { - - for ( var i = 0; i < this.options.length; i ++ ) { - - var element = this.options[ i ]; - - if ( element.value === value ) { - - element.classList.add( 'active' ); - - // scroll into view - - var y = element.offsetTop - this.dom.offsetTop; - var bottomY = y + element.offsetHeight; - var minScroll = bottomY - this.dom.offsetHeight; - - if ( this.dom.scrollTop > y ) { - - this.dom.scrollTop = y - - } else if ( this.dom.scrollTop < minScroll ) { - - this.dom.scrollTop = minScroll; - - } - - this.selectedIndex = i; - - } else { - - element.classList.remove( 'active' ); - - } - - } - - this.selectedValue = value; - - return this; - -}; - - // Checkbox UI.Checkbox = function ( boolean ) { @@ -793,8 +640,8 @@ UI.Number = function ( number ) { var distance = 0; var onMouseDownValue = 0; - var pointer = new THREE.Vector2(); - var prevPointer = new THREE.Vector2(); + var pointer = [ 0, 0 ]; + var prevPointer = [ 0, 0 ]; var onMouseDown = function ( event ) { @@ -804,7 +651,7 @@ UI.Number = function ( number ) { onMouseDownValue = parseFloat( dom.value ); - prevPointer.set( event.clientX, event.clientY ); + prevPointer = [ event.clientX, event.clientY ]; document.addEventListener( 'mousemove', onMouseMove, false ); document.addEventListener( 'mouseup', onMouseUp, false ); @@ -815,9 +662,9 @@ UI.Number = function ( number ) { var currentValue = dom.value; - pointer.set( event.clientX, event.clientY ); + pointer = [ event.clientX, event.clientY ]; - distance += ( pointer.x - prevPointer.x ) - ( pointer.y - prevPointer.y ); + distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] ); var number = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step; @@ -825,7 +672,7 @@ UI.Number = function ( number ) { if ( currentValue !== dom.value ) dom.dispatchEvent( changeEvent ); - prevPointer.set( event.clientX, event.clientY ); + prevPointer = [ event.clientX, event.clientY ]; }; @@ -957,8 +804,8 @@ UI.Integer = function ( number ) { var distance = 0; var onMouseDownValue = 0; - var pointer = new THREE.Vector2(); - var prevPointer = new THREE.Vector2(); + var pointer = [ 0, 0 ]; + var prevPointer = [ 0, 0 ]; var onMouseDown = function ( event ) { @@ -968,7 +815,7 @@ UI.Integer = function ( number ) { onMouseDownValue = parseFloat( dom.value ); - prevPointer.set( event.clientX, event.clientY ); + prevPointer = [ event.clientX, event.clientY ]; document.addEventListener( 'mousemove', onMouseMove, false ); document.addEventListener( 'mouseup', onMouseUp, false ); @@ -979,9 +826,9 @@ UI.Integer = function ( number ) { var currentValue = dom.value; - pointer.set( event.clientX, event.clientY ); + pointer = [ event.clientX, event.clientY ]; - distance += ( pointer.x - prevPointer.x ) - ( pointer.y - prevPointer.y ); + distance += ( pointer[ 0 ] - prevPointer[ 0 ] ) - ( pointer[ 1 ] - prevPointer[ 1 ] ); var number = onMouseDownValue + ( distance / ( event.shiftKey ? 5 : 50 ) ) * scope.step; @@ -989,7 +836,7 @@ UI.Integer = function ( number ) { if ( currentValue !== dom.value ) dom.dispatchEvent( changeEvent ); - prevPointer.set( event.clientX, event.clientY ); + prevPointer = [ event.clientX, event.clientY ]; }; @@ -1154,7 +1001,7 @@ UI.Button.prototype.setLabel = function ( value ) { UI.Dialog = function ( value ) { var scope = this; - + var dom = document.createElement( 'dialog' ); if ( dom.showModal === undefined ) { diff --git a/editor/js/libs/ui.three.js b/editor/js/libs/ui.three.js index e94c04c7725289..0d2842d1c187b9 100644 --- a/editor/js/libs/ui.three.js +++ b/editor/js/libs/ui.three.js @@ -133,3 +133,179 @@ UI.Texture.prototype.onChange = function ( callback ) { return this; }; + +// Outliner + +UI.Outliner = function ( editor ) { + + UI.Element.call( this ); + + var scope = this; + + var dom = document.createElement( 'div' ); + dom.className = 'Outliner'; + dom.tabIndex = 0; // keyup event is ignored without setting tabIndex + + var scene = editor.scene; + + var sortable = Sortable.create( dom, { + draggable: '.draggable', + onUpdate: function ( event ) { + + var item = event.item; + + var object = scene.getObjectById( item.value ); + + if ( item.nextSibling === null ) { + + editor.moveObject( object, editor.scene ); + + } else { + + var nextObject = scene.getObjectById( item.nextSibling.value ); + editor.moveObject( object, nextObject.parent, nextObject ); + + } + + } + } ); + + // Broadcast for object selection after arrow navigation + var changeEvent = document.createEvent('HTMLEvents'); + changeEvent.initEvent( 'change', true, true ); + + // Prevent native scroll behavior + dom.addEventListener( 'keydown', function (event) { + + switch ( event.keyCode ) { + case 38: // up + case 40: // down + event.preventDefault(); + event.stopPropagation(); + break; + } + + }, false); + + // Keybindings to support arrow navigation + dom.addEventListener( 'keyup', function (event) { + + switch ( event.keyCode ) { + case 38: // up + case 40: // down + scope.selectedIndex += ( event.keyCode == 38 ) ? -1 : 1; + + if ( scope.selectedIndex >= 0 && scope.selectedIndex < scope.options.length ) { + + // Highlight selected dom elem and scroll parent if needed + scope.setValue( scope.options[ scope.selectedIndex ].value ); + + scope.dom.dispatchEvent( changeEvent ); + + } + + break; + } + + }, false); + + this.dom = dom; + + this.options = []; + this.selectedIndex = -1; + this.selectedValue = null; + + return this; + +}; + +UI.Outliner.prototype = Object.create( UI.Element.prototype ); +UI.Outliner.prototype.constructor = UI.Outliner; + +UI.Outliner.prototype.setOptions = function ( options ) { + + var scope = this; + + var changeEvent = document.createEvent( 'HTMLEvents' ); + changeEvent.initEvent( 'change', true, true ); + + while ( scope.dom.children.length > 0 ) { + + scope.dom.removeChild( scope.dom.firstChild ); + + } + + scope.options = []; + + for ( var i = 0; i < options.length; i ++ ) { + + var option = options[ i ]; + + var div = document.createElement( 'div' ); + div.className = 'option ' + ( option.static === true ? '': 'draggable' ); + div.innerHTML = option.html; + div.value = option.value; + scope.dom.appendChild( div ); + + scope.options.push( div ); + + div.addEventListener( 'click', function ( event ) { + + scope.setValue( this.value ); + scope.dom.dispatchEvent( changeEvent ); + + }, false ); + + } + + return scope; + +}; + +UI.Outliner.prototype.getValue = function () { + + return this.selectedValue; + +}; + +UI.Outliner.prototype.setValue = function ( value ) { + + for ( var i = 0; i < this.options.length; i ++ ) { + + var element = this.options[ i ]; + + if ( element.value === value ) { + + element.classList.add( 'active' ); + + // scroll into view + + var y = element.offsetTop - this.dom.offsetTop; + var bottomY = y + element.offsetHeight; + var minScroll = bottomY - this.dom.offsetHeight; + + if ( this.dom.scrollTop > y ) { + + this.dom.scrollTop = y + + } else if ( this.dom.scrollTop < minScroll ) { + + this.dom.scrollTop = minScroll; + + } + + this.selectedIndex = i; + + } else { + + element.classList.remove( 'active' ); + + } + + } + + this.selectedValue = value; + + return this; + +}; diff --git a/examples/index.html b/examples/index.html index f603d31afe931f..96acb3951a45c4 100644 --- a/examples/index.html +++ b/examples/index.html @@ -183,7 +183,7 @@

three.js / examples

- + - + @@ -186,8 +176,6 @@ stats.domElement.style.zIndex = 100; container.appendChild( stats.domElement ); - $( "start" ).addEventListener( 'click', onStartClick, false ); - var callbackProgress = function( progress, result ) { var bar = 250, @@ -207,8 +195,6 @@ $( "message" ).style.display = "none"; $( "progressbar" ).style.display = "none"; - $( "start" ).style.display = "block"; - $( "start" ).className = "enabled"; result.scene.traverse( function ( object ) { @@ -237,6 +223,16 @@ } ); + // + + $( "progress" ).style.display = "none"; + + camera = loaded.currentCamera; + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + + scene = loaded.scene; + } $( "progress" ).style.display = "block"; @@ -276,24 +272,6 @@ } - function setButtonActive( id ) { - - $( "start" ).style.backgroundColor = "green"; - - } - - function onStartClick() { - - $( "progress" ).style.display = "none"; - - camera = loaded.currentCamera; - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - scene = loaded.scene; - - } - function onDocumentMouseMove( event ) { mouseX = ( event.clientX - windowHalfX ); diff --git a/examples/webgl_materials_cars.html b/examples/webgl_materials_cars.html index a21970f2f42040..0a5fc46d1fbce7 100644 --- a/examples/webgl_materials_cars.html +++ b/examples/webgl_materials_cars.html @@ -250,7 +250,7 @@ "Carmine": new THREE.MeshPhongMaterial( { color: 0x770000, specular:0xffaaaa, envMap: textureCube, combine: THREE.MultiplyOperation } ), "Gold": new THREE.MeshPhongMaterial( { color: 0xaa9944, specular:0xbbaa99, shininess:50, envMap: textureCube, combine: THREE.MultiplyOperation } ), "Bronze": new THREE.MeshPhongMaterial( { color: 0x150505, specular:0xee6600, shininess:10, envMap: textureCube, combine: THREE.MixOperation, reflectivity: 0.25 } ), - "Chrome": new THREE.MeshPhongMaterial( { color: 0xffffff, specular:0xffffff, envMap: textureCube, combine: THREE.Multiply } ), + "Chrome": new THREE.MeshPhongMaterial( { color: 0xffffff, specular:0xffffff, envMap: textureCube, combine: THREE.MultiplyOperation } ), "Orange metal": new THREE.MeshLambertMaterial( { color: 0xff6600, envMap: textureCube, combine: THREE.MultiplyOperation } ), "Blue metal": new THREE.MeshLambertMaterial( { color: 0x001133, envMap: textureCube, combine: THREE.MultiplyOperation } ), diff --git a/examples/webgl_materials_lightmap.html b/examples/webgl_materials_lightmap.html index 7d758e93f0d519..7b845ddc3b0cbe 100644 --- a/examples/webgl_materials_lightmap.html +++ b/examples/webgl_materials_lightmap.html @@ -100,14 +100,13 @@ // LIGHTS - var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.475 ); + var directionalLight = new THREE.DirectionalLight( 0x333333, 2 ); directionalLight.position.set( 100, 100, -100 ); scene.add( directionalLight ); - var hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 1.25 ); - hemiLight.color.setHSL( 0.6, 1, 0.75 ); - hemiLight.groundColor.setHSL( 0.1, 0.8, 0.7 ); + var hemiLight = new THREE.HemisphereLight( 0xaabbff, 0x040404, 1 ); + hemiLight.position.y = 500; scene.add( hemiLight ); diff --git a/examples/webgl_mirror.html b/examples/webgl_mirror.html index 4d306530785923..86fba1dc97d50d 100644 --- a/examples/webgl_mirror.html +++ b/examples/webgl_mirror.html @@ -86,7 +86,7 @@ var planeGeo = new THREE.PlaneBufferGeometry( 100.1, 100.1 ); - // MIRORR planes + // MIRROR planes groundMirror = new THREE.Mirror( renderer, camera, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color: 0x777777 } ); var mirrorMesh = new THREE.Mesh( planeGeo, groundMirror.material ); diff --git a/examples/webgl_shaders_ocean2.html b/examples/webgl_shaders_ocean2.html index dcd1806d6041bd..1684fde1c3419e 100644 --- a/examples/webgl_shaders_ocean2.html +++ b/examples/webgl_shaders_ocean2.html @@ -7,20 +7,50 @@ body { margin: 0px; overflow: hidden; + font-family: Monospace; + text-align: center; } + #info { + color: #fff; + position: absolute; + top: 10px; + width: 100%; + } + a { + color: #09f; + } + #type-status { + font-weight: bold; + } + #stats { position: absolute; top:0; left: 0 } +
+ three.js - webgl ocean simulation
+ current simulation framebuffers type is
+ change type to +
+ + + + + diff --git a/examples/webgl_terrain_dynamic.html b/examples/webgl_terrain_dynamic.html index 1a143c6a512395..5b3fe0dabd4218 100644 --- a/examples/webgl_terrain_dynamic.html +++ b/examples/webgl_terrain_dynamic.html @@ -606,7 +606,7 @@ var sceneTmp = new THREE.Scene(); - var meshTmp = new THREE.Mesh( new THREE.PlaneGeometry( SCREEN_WIDTH, SCREEN_HEIGHT ), shaderMaterial ); + var meshTmp = new THREE.Mesh( new THREE.PlaneBufferGeometry( SCREEN_WIDTH, SCREEN_HEIGHT ), shaderMaterial ); meshTmp.position.z = -500; sceneTmp.add( meshTmp ); diff --git a/src/Three.js b/src/Three.js index 632e7d3c47fb41..61cb895796ca63 100644 --- a/src/Three.js +++ b/src/Three.js @@ -16,14 +16,23 @@ if ( typeof module === 'object' ) { if ( Math.sign === undefined ) { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign + Math.sign = function ( x ) { - return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0; + return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : +x; }; } + +// set the default log handlers +THREE.log = function() { console.log.apply( console, arguments ); } +THREE.warn = function() { console.warn.apply( console, arguments ); } +THREE.error = function() { console.error.apply( console, arguments ); } + + // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; @@ -149,6 +158,7 @@ THREE.UnsignedShortType = 1012; THREE.IntType = 1013; THREE.UnsignedIntType = 1014; THREE.FloatType = 1015; +THREE.HalfFloatType = 1025; // Pixel types @@ -187,25 +197,25 @@ THREE.RGBA_PVRTC_2BPPV1_Format = 2103; THREE.Projector = function () { - console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); + THREE.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); this.projectVector = function ( vector, camera ) { - console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); + THREE.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); vector.project( camera ); }; this.unprojectVector = function ( vector, camera ) { - console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); + THREE.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); vector.unproject( camera ); }; this.pickingRay = function ( vector, camera ) { - console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); + THREE.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); }; @@ -213,7 +223,7 @@ THREE.Projector = function () { THREE.CanvasRenderer = function () { - console.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); + THREE.error( 'THREE.CanvasRenderer has been moved to /examples/js/renderers/CanvasRenderer.js' ); this.domElement = document.createElement( 'canvas' ); this.clear = function () {}; diff --git a/src/core/BufferAttribute.js b/src/core/BufferAttribute.js index d19a4aeed2d8a4..419a0665e156fa 100644 --- a/src/core/BufferAttribute.js +++ b/src/core/BufferAttribute.js @@ -32,11 +32,15 @@ THREE.BufferAttribute.prototype = { } + return this; + }, - set: function ( value ) { + set: function ( value, offset ) { + + if ( offset === undefined ) offset = 0; - this.array.set( value ); + this.array.set( value, offset ); return this; @@ -114,21 +118,21 @@ THREE.BufferAttribute.prototype = { THREE.Int8Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Uint8Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Uint8ClampedAttribute = function ( data, itemSize ) { - console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); @@ -136,42 +140,42 @@ THREE.Uint8ClampedAttribute = function ( data, itemSize ) { THREE.Int16Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Uint16Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Int32Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Uint32Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Float32Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; THREE.Float64Attribute = function ( data, itemSize ) { - console.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); + THREE.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' ); return new THREE.BufferAttribute( data, itemSize ); }; diff --git a/src/core/BufferGeometry.js b/src/core/BufferGeometry.js index 173d6206a48bf6..256873ef8cdf20 100644 --- a/src/core/BufferGeometry.js +++ b/src/core/BufferGeometry.js @@ -31,7 +31,7 @@ THREE.BufferGeometry.prototype = { if ( attribute instanceof THREE.BufferAttribute === false ) { - console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); + THREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] }; @@ -84,11 +84,29 @@ THREE.BufferGeometry.prototype = { } + if ( this.boundingBox !== null ) { + + this.computeBoundingBox(); + + } + + if ( this.boundingSphere !== null ) { + + this.computeBoundingSphere(); + + } + }, center: function () { - // TODO + this.computeBoundingBox(); + + var offset = this.boundingBox.center().negate(); + + this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); + + return offset; }, @@ -277,7 +295,7 @@ THREE.BufferGeometry.prototype = { if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' ); + THREE.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' ); } @@ -331,7 +349,7 @@ THREE.BufferGeometry.prototype = { if ( isNaN( this.boundingSphere.radius ) ) { - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' ); + THREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' ); } @@ -476,7 +494,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.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' ); return; } @@ -649,24 +667,18 @@ THREE.BufferGeometry.prototype = { }, /* - 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. + 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. + size - 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. + computeOffsets: function ( size ) { - var s = Date.now(); + if ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit. var indices = this.attributes.index.array; var vertices = this.attributes.position.array; - var verticesCount = ( vertices.length / 3 ); var facesCount = ( indices.length / 3 ); /* @@ -746,7 +758,8 @@ THREE.BufferGeometry.prototype = { /* 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; + this.offsets = offsets; // TODO: Deprecate + this.drawcalls = offsets; /* var orderTime = Date.now(); @@ -764,7 +777,7 @@ THREE.BufferGeometry.prototype = { if ( geometry instanceof THREE.BufferGeometry === false ) { - console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); + THREE.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); return; } @@ -884,13 +897,7 @@ THREE.BufferGeometry.prototype = { var attribute = attributes[ key ]; - var array = [], typeArray = attribute.array; - - for ( var i = 0, l = typeArray.length; i < l; i ++ ) { - - array[ i ] = typeArray[ i ]; - - } + var array = Array.prototype.slice.call( attribute.array ); output.data.attributes[ key ] = { itemSize: attribute.itemSize, diff --git a/src/core/DynamicBufferAttribute.js b/src/core/DynamicBufferAttribute.js new file mode 100644 index 00000000000000..17610aa25bb76a --- /dev/null +++ b/src/core/DynamicBufferAttribute.js @@ -0,0 +1,21 @@ +/** + * @author benaadams / https://twitter.com/ben_a_adams + * @author mrdoob / http://mrdoob.com/ + */ + +THREE.DynamicBufferAttribute = function ( array, itemSize ) { + + THREE.BufferAttribute.call( this, array, itemSize ); + + this.updateRange = { offset: 0, count: -1 }; + +}; + +THREE.DynamicBufferAttribute.prototype = Object.create( THREE.BufferAttribute.prototype ); +THREE.DynamicBufferAttribute.prototype.constructor = THREE.DynamicBufferAttribute; + +THREE.DynamicBufferAttribute.prototype.clone = function () { + + return new THREE.DynamicBufferAttribute( new this.array.constructor( this.array ), this.itemSize ); + +}; diff --git a/src/core/Face4.js b/src/core/Face4.js index ee2b05556d48ee..31ab7f85f2796e 100644 --- a/src/core/Face4.js +++ b/src/core/Face4.js @@ -4,7 +4,7 @@ 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.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ) return new THREE.Face3( a, b, c, normal, color, materialIndex ); }; diff --git a/src/core/Geometry.js b/src/core/Geometry.js index 69307159117a82..3a571c39c2927a 100644 --- a/src/core/Geometry.js +++ b/src/core/Geometry.js @@ -81,18 +81,21 @@ THREE.Geometry.prototype = { } - if ( this.boundingBox instanceof THREE.Box3 ) { + if ( this.boundingBox !== null ) { this.computeBoundingBox(); } - if ( this.boundingSphere instanceof THREE.Sphere ) { + if ( this.boundingSphere !== null ) { this.computeBoundingSphere(); } + this.verticesNeedUpdate = true; + this.normalsNeedUpdate = true; + }, fromBufferGeometry: function ( geometry ) { @@ -151,9 +154,33 @@ THREE.Geometry.prototype = { if ( indices !== undefined ) { - for ( var i = 0; i < indices.length; i += 3 ) { + var drawcalls = geometry.drawcalls; + + if ( drawcalls.length > 0 ) { + + for ( var i = 0; i < drawcalls.length; i ++ ) { + + var drawcall = drawcalls[ i ]; + + var start = drawcall.start; + var count = drawcall.count; + var index = drawcall.index; - addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + for ( var j = start, jl = start + count; j < jl; j += 3 ) { + + addFace( index + indices[ j ], index + indices[ j + 1 ], index + indices[ j + 2 ] ); + + } + + } + + } else { + + for ( var i = 0; i < indices.length; i += 3 ) { + + addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + + } } @@ -189,13 +216,9 @@ THREE.Geometry.prototype = { this.computeBoundingBox(); - var offset = new THREE.Vector3(); + var offset = this.boundingBox.center().negate(); - offset.addVectors( this.boundingBox.min, this.boundingBox.max ); - offset.multiplyScalar( - 0.5 ); - - this.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); - this.computeBoundingBox(); + this.applyMatrix( new THREE.Matrix4().setPosition( offset ) ); return offset; @@ -242,9 +265,8 @@ THREE.Geometry.prototype = { // 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(); + var vA, vB, vC; + var cb = new THREE.Vector3(), ab = new THREE.Vector3(); for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { @@ -418,7 +440,7 @@ THREE.Geometry.prototype = { // based on http://www.terathon.com/code/tangent.html // tangents go to vertices - var f, fl, v, vl, i, il, vertexIndex, + var f, fl, v, vl, i, vertexIndex, face, uv, vA, vB, vC, uvA, uvB, uvC, x1, x2, y1, y2, z1, z2, s1, s2, t1, t2, r, t, test, @@ -565,7 +587,7 @@ THREE.Geometry.prototype = { if ( geometry instanceof THREE.Geometry === false ) { - console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); + THREE.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); return; } @@ -675,7 +697,7 @@ THREE.Geometry.prototype = { if ( mesh instanceof THREE.Mesh === false ) { - console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); + THREE.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); return; } @@ -700,8 +722,8 @@ THREE.Geometry.prototype = { 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; + var i, il, face; + var indices, j, jl; for ( i = 0, il = this.vertices.length; i < il; i ++ ) { diff --git a/src/core/Object3D.js b/src/core/Object3D.js index 0d4e94102b0837..e28dd71f342172 100644 --- a/src/core/Object3D.js +++ b/src/core/Object3D.js @@ -19,8 +19,6 @@ THREE.Object3D = function () { this.up = THREE.Object3D.DefaultUp.clone(); - var scope = this; - var position = new THREE.Vector3(); var rotation = new THREE.Euler(); var quaternion = new THREE.Quaternion(); @@ -53,7 +51,7 @@ THREE.Object3D = function () { scale: { enumerable: true, value: scale - }, + } } ); this.rotationAutoUpdate = true; @@ -70,6 +68,7 @@ THREE.Object3D = function () { this.receiveShadow = false; this.frustumCulled = true; + this.renderOrder = 0; this.userData = {}; @@ -83,7 +82,7 @@ THREE.Object3D.prototype = { get eulerOrder () { - console.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); + THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); return this.rotation.order; @@ -91,7 +90,7 @@ THREE.Object3D.prototype = { set eulerOrder ( value ) { - console.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); + THREE.warn( 'THREE.Object3D: .eulerOrder has been moved to .rotation.order.' ); this.rotation.order = value; @@ -99,13 +98,13 @@ THREE.Object3D.prototype = { get useQuaternion () { - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); }, set useQuaternion ( value ) { - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + THREE.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); }, @@ -223,7 +222,7 @@ THREE.Object3D.prototype = { translate: function ( distance, axis ) { - console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); + THREE.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); return this.translateOnAxis( axis, distance ); }, @@ -302,7 +301,7 @@ THREE.Object3D.prototype = { if ( arguments.length > 1 ) { - for ( var i = 0; i < arguments.length; i++ ) { + for ( var i = 0; i < arguments.length; i ++ ) { this.add( arguments[ i ] ); @@ -314,7 +313,7 @@ THREE.Object3D.prototype = { if ( object === this ) { - console.error( "THREE.Object3D.add:", object, "can't be added as a child of itself." ); + THREE.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); return this; } @@ -334,7 +333,7 @@ THREE.Object3D.prototype = { } else { - console.error( "THREE.Object3D.add:", object, "is not an instance of THREE.Object3D." ); + THREE.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); } @@ -346,7 +345,7 @@ THREE.Object3D.prototype = { if ( arguments.length > 1 ) { - for ( var i = 0; i < arguments.length; i++ ) { + for ( var i = 0; i < arguments.length; i ++ ) { this.remove( arguments[ i ] ); @@ -370,7 +369,7 @@ THREE.Object3D.prototype = { getChildByName: function ( name ) { - console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); + THREE.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); return this.getObjectByName( name ); }, @@ -677,6 +676,7 @@ THREE.Object3D.prototype = { data.color = object.color.getHex(); data.intensity = object.intensity; data.distance = object.distance; + data.decay = object.decay; } else if ( object instanceof THREE.SpotLight ) { @@ -685,21 +685,19 @@ THREE.Object3D.prototype = { data.distance = object.distance; data.angle = object.angle; data.exponent = object.exponent; + data.decay = object.decay; } else if ( object instanceof THREE.HemisphereLight ) { data.color = object.color.getHex(); data.groundColor = object.groundColor.getHex(); - } else if ( object instanceof THREE.Mesh ) { + } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.PointCloud ) { data.geometry = parseGeometry( object.geometry ); data.material = parseMaterial( object.material ); - } else if ( object instanceof THREE.Line ) { - - data.geometry = parseGeometry( object.geometry ); - data.material = parseMaterial( object.material ); + if ( object instanceof THREE.Line ) data.mode = object.mode; } else if ( object instanceof THREE.Sprite ) { diff --git a/src/core/Raycaster.js b/src/core/Raycaster.js index 5f06777084f4f2..104f487b2b09d2 100644 --- a/src/core/Raycaster.js +++ b/src/core/Raycaster.js @@ -81,7 +81,7 @@ } else { - console.error( 'THREE.Raycaster: Unsupported camera type.' ); + THREE.error( 'THREE.Raycaster: Unsupported camera type.' ); } @@ -105,7 +105,7 @@ if ( objects instanceof Array === false ) { - console.log( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); + THREE.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); return intersects; } diff --git a/src/extras/FontUtils.js b/src/extras/FontUtils.js index 49a9f38ec93a4e..64efa1727b0c10 100644 --- a/src/extras/FontUtils.js +++ b/src/extras/FontUtils.js @@ -56,7 +56,7 @@ THREE.FontUtils = { 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; + ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; return data; @@ -64,11 +64,9 @@ THREE.FontUtils = { drawText: function ( text ) { - var characterPts = [], allPts = []; - // RenderText - var i, p, + var i, face = this.getFace(), scale = this.size / face.resolution, offset = 0, @@ -156,7 +154,7 @@ THREE.FontUtils = { x = outline[ i ++ ] * scaleX + offset; y = outline[ i ++ ] * scaleY; - path.lineTo( x,y ); + path.lineTo( x, y ); break; case 'q': @@ -180,13 +178,13 @@ THREE.FontUtils = { 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 ); - } + THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); + THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); + } - } + } - break; + break; case 'b': @@ -211,8 +209,8 @@ THREE.FontUtils = { 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 ); + THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); + THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); } @@ -333,7 +331,7 @@ THREE.FontUtils.generateShapes = function ( text, parameters ) { //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.warn( 'THREE.FontUtils: Warning, unable to triangulate polygon! in Triangulate.process()' ); if ( indices ) return vertIndices; return result; @@ -367,7 +365,7 @@ THREE.FontUtils.generateShapes = function ( text, parameters ) { /* remove v from the remaining polygon */ - for ( s = v, t = v + 1; t < nv; s++, t++ ) { + for ( s = v, t = v + 1; t < nv; s ++, t ++ ) { verts[ s ] = verts[ t ]; diff --git a/src/extras/GeometryUtils.js b/src/extras/GeometryUtils.js index ca413e216563e2..4284df3b976e45 100644 --- a/src/extras/GeometryUtils.js +++ b/src/extras/GeometryUtils.js @@ -6,7 +6,7 @@ THREE.GeometryUtils = { merge: function ( geometry1, geometry2, materialIndexOffset ) { - console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); + THREE.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); var matrix; @@ -25,7 +25,7 @@ THREE.GeometryUtils = { center: function ( geometry ) { - console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); + THREE.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); return geometry.center(); } diff --git a/src/extras/ImageUtils.js b/src/extras/ImageUtils.js index 720c9530b2cc2c..b841603a56ca2b 100644 --- a/src/extras/ImageUtils.js +++ b/src/extras/ImageUtils.js @@ -81,13 +81,13 @@ THREE.ImageUtils = { loadCompressedTexture: function () { - console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) + THREE.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ) }, loadCompressedTextureCube: function () { - console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) + THREE.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ) }, @@ -144,7 +144,7 @@ THREE.ImageUtils = { 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, - 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 ] ); diff --git a/src/extras/animation/Animation.js b/src/extras/animation/Animation.js index aeaf5823e515c3..07b8171a716475 100644 --- a/src/extras/animation/Animation.js +++ b/src/extras/animation/Animation.js @@ -21,383 +21,386 @@ THREE.Animation = function ( root, data ) { }; +THREE.Animation.prototype = { -THREE.Animation.prototype.keyTypes = [ "pos", "rot", "scl" ]; + constructor: THREE.Animation, + keyTypes: [ "pos", "rot", "scl" ], -THREE.Animation.prototype.play = function ( startTime, weight ) { + play: function ( startTime, weight ) { - this.currentTime = startTime !== undefined ? startTime : 0; - this.weight = weight !== undefined ? weight: 1; + this.currentTime = startTime !== undefined ? startTime : 0; + this.weight = weight !== undefined ? weight : 1; - this.isPlaying = true; + this.isPlaying = true; - this.reset(); + this.reset(); - THREE.AnimationHandler.play( this ); + THREE.AnimationHandler.play( this ); -}; + }, + stop: function() { -THREE.Animation.prototype.stop = function() { + this.isPlaying = false; - this.isPlaying = false; + THREE.AnimationHandler.stop( this ); - THREE.AnimationHandler.stop( this ); + }, -}; + reset: function () { -THREE.Animation.prototype.reset = function () { + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + var object = this.hierarchy[ h ]; - var object = this.hierarchy[ h ]; + if ( object.animationCache === undefined ) { - if ( object.animationCache === undefined ) { + object.animationCache = { + animations: {}, + blending: { + positionWeight: 0.0, + quaternionWeight: 0.0, + scaleWeight: 0.0 + } + }; + } - object.animationCache = { - animations: {}, - blending: { - positionWeight: 0.0, - quaternionWeight: 0.0, - scaleWeight: 0.0 - } - }; - } + var name = this.data.name; + var animations = object.animationCache.animations; + var animationCache = animations[ name ]; - if ( object.animationCache.animations[this.data.name] === undefined ) { + if ( animationCache === undefined ) { - object.animationCache.animations[this.data.name] = {}; - object.animationCache.animations[this.data.name].prevKey = { pos: 0, rot: 0, scl: 0 }; - object.animationCache.animations[this.data.name].nextKey = { pos: 0, rot: 0, scl: 0 }; - object.animationCache.animations[this.data.name].originalMatrix = object.matrix; + animationCache = { + prevKey: { pos: 0, rot: 0, scl: 0 }, + nextKey: { pos: 0, rot: 0, scl: 0 }, + originalMatrix: object.matrix + }; - } + animations[ name ] = animationCache; - var animationCache = object.animationCache.animations[this.data.name]; + } - // Get keys to match our current time + // Get keys to match our current time - for ( var t = 0; t < 3; t ++ ) { + for ( var t = 0; t < 3; t ++ ) { - var type = this.keyTypes[ t ]; + var type = this.keyTypes[ t ]; - var prevKey = this.data.hierarchy[ h ].keys[ 0 ]; - var nextKey = this.getNextKeyWith( type, h, 1 ); + var prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + var nextKey = this.getNextKeyWith( type, h, 1 ); - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - prevKey = nextKey; - nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - } + } + + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; - animationCache.prevKey[ type ] = prevKey; - animationCache.nextKey[ type ] = nextKey; + } } - } + }, -}; + resetBlendWeights: function () { + + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { -THREE.Animation.prototype.resetBlendWeights = function () { + var object = this.hierarchy[ h ]; + var animationCache = object.animationCache; - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + if ( animationCache !== undefined ) { - var object = this.hierarchy[ h ]; + var blending = animationCache.blending; - if ( object.animationCache !== undefined ) { + blending.positionWeight = 0.0; + blending.quaternionWeight = 0.0; + blending.scaleWeight = 0.0; - object.animationCache.blending.positionWeight = 0.0; - object.animationCache.blending.quaternionWeight = 0.0; - object.animationCache.blending.scaleWeight = 0.0; + } } - } + }, -}; + update: ( function() { -THREE.Animation.prototype.update = (function(){ + var points = []; + var target = new THREE.Vector3(); + var newVector = new THREE.Vector3(); + var newQuat = new THREE.Quaternion(); - var points = []; - var target = new THREE.Vector3(); - var newVector = new THREE.Vector3(); - var newQuat = new THREE.Quaternion(); + // Catmull-Rom spline - // Catmull-Rom spline + var interpolateCatmullRom = function ( points, scale ) { - var interpolateCatmullRom = function ( points, scale ) { + var c = [], v3 = [], + point, intPoint, weight, w2, w3, + pa, pb, pc, pd; - var c = [], v3 = [], - point, intPoint, weight, w2, w3, - pa, pb, pc, pd; + point = ( points.length - 1 ) * scale; + intPoint = Math.floor( point ); + weight = point - intPoint; - 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; - 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 ] ]; - pa = points[ c[ 0 ] ]; - pb = points[ c[ 1 ] ]; - pc = points[ c[ 2 ] ]; - pd = points[ c[ 3 ] ]; + w2 = weight * weight; + w3 = weight * w2; - 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 ); - 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; - return v3; + }; - }; + var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { - var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { + var v0 = ( p2 - p0 ) * 0.5, + v1 = ( p3 - p1 ) * 0.5; - 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 ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; + }; - }; + return function ( delta ) { - return function ( delta ) { + if ( this.isPlaying === false ) return; - if ( this.isPlaying === false ) return; + this.currentTime += delta * this.timeScale; - this.currentTime += delta * this.timeScale; + if ( this.weight === 0 ) + return; - if ( this.weight === 0 ) - return; + // - // + var duration = this.data.length; - var duration = this.data.length; + if ( this.currentTime > duration || this.currentTime < 0 ) { - if ( this.currentTime > duration || this.currentTime < 0 ) { + if ( this.loop ) { - if ( this.loop ) { + this.currentTime %= duration; - this.currentTime %= duration; + if ( this.currentTime < 0 ) + this.currentTime += duration; - if ( this.currentTime < 0 ) - this.currentTime += duration; + this.reset(); - this.reset(); + } else { - } else { + this.stop(); - this.stop(); + } } - } + for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + var object = this.hierarchy[ h ]; + var animationCache = object.animationCache.animations[this.data.name]; + var blending = object.animationCache.blending; - var object = this.hierarchy[ h ]; - var animationCache = object.animationCache.animations[this.data.name]; - var blending = object.animationCache.blending; + // loop through pos/rot/scl - // loop through pos/rot/scl + for ( var t = 0; t < 3; t ++ ) { - for ( var t = 0; t < 3; t ++ ) { + // get keys - // get keys + var type = this.keyTypes[ t ]; + var prevKey = animationCache.prevKey[ type ]; + var nextKey = animationCache.nextKey[ type ]; - var type = this.keyTypes[ t ]; - var prevKey = animationCache.prevKey[ type ]; - var nextKey = animationCache.nextKey[ type ]; + if ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) || + ( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) { - if ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) || - ( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) { + prevKey = this.data.hierarchy[ h ].keys[ 0 ]; + nextKey = this.getNextKeyWith( type, h, 1 ); - prevKey = this.data.hierarchy[ h ].keys[ 0 ]; - nextKey = this.getNextKeyWith( type, h, 1 ); + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { + prevKey = nextKey; + nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); - prevKey = nextKey; - nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); + } + + animationCache.prevKey[ type ] = prevKey; + animationCache.nextKey[ type ] = nextKey; } - animationCache.prevKey[ type ] = prevKey; - animationCache.nextKey[ type ] = nextKey; + var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); - } + var prevXYZ = prevKey[ type ]; + var nextXYZ = nextKey[ type ]; - var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); + if ( scale < 0 ) scale = 0; + if ( scale > 1 ) scale = 1; - var prevXYZ = prevKey[ type ]; - var nextXYZ = nextKey[ type ]; + // interpolate - if ( scale < 0 ) scale = 0; - if ( scale > 1 ) scale = 1; + if ( type === "pos" ) { - // interpolate + if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { - if ( type === "pos" ) { + newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { + // blend + var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); + object.position.lerp( newVector, proportionalWeight ); + blending.positionWeight += this.weight; - newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - // blend - var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); - object.position.lerp( newVector, proportionalWeight ); - blending.positionWeight += this.weight; + 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" ]; - } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + scale = scale * 0.33 + 0.33; - 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" ]; + var currentPoint = interpolateCatmullRom( points, scale ); + var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); + blending.positionWeight += this.weight; - scale = scale * 0.33 + 0.33; + // blend - var currentPoint = interpolateCatmullRom( points, scale ); - var proportionalWeight = this.weight / ( this.weight + blending.positionWeight ); - blending.positionWeight += this.weight; + var vector = object.position; - // blend + vector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight; + vector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight; + vector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight; - var vector = object.position; - - vector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight; - vector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight; - vector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight; + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); - var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); + target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); + target.sub( vector ); + target.y = 0; + target.normalize(); - 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 ); - var angle = Math.atan2( target.x, target.z ); - object.rotation.set( 0, angle, 0 ); + } } - } + } else if ( type === "rot" ) { - } else if ( type === "rot" ) { + THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale ); - THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale ); + // Avoid paying the cost of an additional slerp if we don't have to + if ( blending.quaternionWeight === 0 ) { - // Avoid paying the cost of an additional slerp if we don't have to - if ( blending.quaternionWeight === 0 ) { + object.quaternion.copy(newQuat); + blending.quaternionWeight = this.weight; - object.quaternion.copy(newQuat); - blending.quaternionWeight = this.weight; + } else { - } else { + var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight ); + THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight ); + blending.quaternionWeight += this.weight; - var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight ); - THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight ); - blending.quaternionWeight += this.weight; + } - } + } else if ( type === "scl" ) { - } else if ( type === "scl" ) { + newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; + newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; + newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; - newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; - newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; - newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; + var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight ); + object.scale.lerp( newVector, proportionalWeight ); + blending.scaleWeight += this.weight; - var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight ); - object.scale.lerp( newVector, proportionalWeight ); - blending.scaleWeight += this.weight; + } } } - } - - return true; - - }; + return true; -})(); + }; + } )(), + getNextKeyWith: function ( type, h, key ) { + var keys = this.data.hierarchy[ h ].keys; + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { -// Get next key with + key = key < keys.length - 1 ? key : keys.length - 1; -THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) { + } else { - var keys = this.data.hierarchy[ h ].keys; + key = key % keys.length; - 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 ) { - for ( ; key < keys.length; key ++ ) { + return keys[ key ]; - if ( keys[ key ][ type ] !== undefined ) { - - return keys[ key ]; + } } - } - - return this.data.hierarchy[ h ].keys[ 0 ]; + return this.data.hierarchy[ h ].keys[ 0 ]; -}; + }, -// Get previous key with + getPrevKeyWith: function ( type, h, key ) { -THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { + var keys = this.data.hierarchy[ h ].keys; - var keys = this.data.hierarchy[ h ].keys; + if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || + this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { - if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || - this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { + key = key > 0 ? key : 0; - key = key > 0 ? key : 0; + } else { - } else { + key = key >= 0 ? key : key + keys.length; - key = key >= 0 ? key : key + keys.length; + } - } + for ( ; key >= 0; key -- ) { - for ( ; key >= 0; key -- ) { + if ( keys[ key ][ type ] !== undefined ) { - if ( keys[ key ][ type ] !== undefined ) { + return keys[ key ]; - return keys[ key ]; + } } - } + return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; - return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; + } }; diff --git a/src/extras/animation/AnimationHandler.js b/src/extras/animation/AnimationHandler.js index 4780ad53b2415a..e50ca2ed045596 100644 --- a/src/extras/animation/AnimationHandler.js +++ b/src/extras/animation/AnimationHandler.js @@ -10,9 +10,9 @@ THREE.AnimationHandler = { // - add: function () { console.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); }, - get: function () { console.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); }, - remove: function () { console.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); }, + add: function () { THREE.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); }, + get: function () { THREE.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); }, + remove: function () { THREE.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); }, // diff --git a/src/extras/animation/KeyFrameAnimation.js b/src/extras/animation/KeyFrameAnimation.js index 3975e7825bc3b3..609c5f21534bde 100644 --- a/src/extras/animation/KeyFrameAnimation.js +++ b/src/extras/animation/KeyFrameAnimation.js @@ -50,195 +50,192 @@ THREE.KeyFrameAnimation = function ( data ) { }; +THREE.KeyFrameAnimation.prototype = { -THREE.KeyFrameAnimation.prototype.play = function ( startTime ) { + constructor: THREE.KeyFrameAnimation, - this.currentTime = startTime !== undefined ? startTime : 0; + play: function ( startTime ) { - if ( this.isPlaying === false ) { + this.currentTime = startTime !== undefined ? startTime : 0; - this.isPlaying = true; + if ( this.isPlaying === false ) { - // reset key cache + this.isPlaying = true; - var h, hl = this.hierarchy.length, - object, - node; + // reset key cache - for ( h = 0; h < hl; h ++ ) { + var h, hl = this.hierarchy.length, + object, + node; - object = this.hierarchy[ h ]; - node = this.data.hierarchy[ h ]; + for ( h = 0; h < hl; h ++ ) { - if ( node.animationCache === undefined ) { + object = this.hierarchy[ h ]; + node = this.data.hierarchy[ h ]; - node.animationCache = {}; - node.animationCache.prevKey = null; - node.animationCache.nextKey = null; - node.animationCache.originalMatrix = object.matrix; + if ( node.animationCache === undefined ) { - } + node.animationCache = {}; + node.animationCache.prevKey = null; + node.animationCache.nextKey = null; + node.animationCache.originalMatrix = object.matrix; + + } + + var keys = this.data.hierarchy[h].keys; - var keys = this.data.hierarchy[h].keys; + if (keys.length) { - if (keys.length) { + node.animationCache.prevKey = keys[ 0 ]; + node.animationCache.nextKey = keys[ 1 ]; - 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.startTime = Math.min( keys[0].time, this.startTime ); - this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); + } } + this.update( 0 ); + } - this.update( 0 ); + this.isPaused = false; - } + THREE.AnimationHandler.play( this ); - this.isPaused = false; + }, - THREE.AnimationHandler.play( this ); + stop: function () { -}; + this.isPlaying = false; + this.isPaused = false; + THREE.AnimationHandler.stop( this ); -THREE.KeyFrameAnimation.prototype.stop = function() { + // reset JIT matrix and remove cache - this.isPlaying = false; - this.isPaused = false; - - THREE.AnimationHandler.stop( this ); + for ( var h = 0; h < this.data.hierarchy.length; h ++ ) { - // reset JIT matrix and remove cache + var obj = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; - 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 ) { - if ( node.animationCache !== undefined ) { + var original = node.animationCache.originalMatrix; - var original = node.animationCache.originalMatrix; + original.copy( obj.matrix ); + obj.matrix = original; - original.copy( obj.matrix ); - obj.matrix = original; + delete node.animationCache; - delete node.animationCache; + } } - } - -}; + }, + update: function ( delta ) { -// Update + if ( this.isPlaying === false ) return; -THREE.KeyFrameAnimation.prototype.update = function ( delta ) { + this.currentTime += delta * this.timeScale; - if ( this.isPlaying === false ) return; + // - this.currentTime += delta * this.timeScale; + var duration = this.data.length; - // + if ( this.loop === true && this.currentTime > duration ) { - var duration = this.data.length; + this.currentTime %= duration; - 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 ++ ) { - this.currentTime = Math.min( this.currentTime, duration ); + var object = this.hierarchy[ h ]; + var node = this.data.hierarchy[ h ]; - for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { + var keys = node.keys, + animationCache = node.animationCache; - 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 ( keys.length ) { + if ( nextKey.time <= this.currentTime ) { - var prevKey = animationCache.prevKey; - var nextKey = animationCache.nextKey; + while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { - if ( nextKey.time <= this.currentTime ) { + prevKey = nextKey; + nextKey = keys[ prevKey.index + 1 ]; - while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { + } - prevKey = nextKey; - nextKey = keys[ prevKey.index + 1 ]; + animationCache.prevKey = prevKey; + animationCache.nextKey = nextKey; } - animationCache.prevKey = prevKey; - animationCache.nextKey = nextKey; + if ( nextKey.time >= this.currentTime ) { - } + prevKey.interpolate( nextKey, this.currentTime ); - if ( nextKey.time >= this.currentTime ) { + } else { - prevKey.interpolate( nextKey, this.currentTime ); + prevKey.interpolate( nextKey, nextKey.time ); - } else { + } - prevKey.interpolate( nextKey, nextKey.time ); + this.data.hierarchy[ h ].node.updateMatrix(); + object.matrixWorldNeedsUpdate = true; } - this.data.hierarchy[ h ].node.updateMatrix(); - object.matrixWorldNeedsUpdate = true; - } - } - -}; + }, -// Get next key with + getNextKeyWith: function ( sid, h, key ) { -THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) { + var keys = this.data.hierarchy[ h ].keys; + key = key % keys.length; - var keys = this.data.hierarchy[ h ].keys; - key = key % keys.length; + for ( ; key < keys.length; key ++ ) { - for ( ; key < keys.length; key ++ ) { + if ( keys[ key ].hasTarget( sid ) ) { - if ( keys[ key ].hasTarget( sid ) ) { + return keys[ key ]; - return keys[ key ]; + } } - } - - return keys[ 0 ]; + return keys[ 0 ]; -}; + }, -// Get previous key with + getPrevKeyWith: function ( sid, h, key ) { -THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { + var keys = this.data.hierarchy[ h ].keys; + key = key >= 0 ? key : key + keys.length; - var keys = this.data.hierarchy[ h ].keys; - key = key >= 0 ? key : key + keys.length; + for ( ; key >= 0; key -- ) { - for ( ; key >= 0; key -- ) { + if ( keys[ key ].hasTarget( sid ) ) { - if ( keys[ key ].hasTarget( sid ) ) { + return keys[ key ]; - return keys[ key ]; + } } - } + return keys[ keys.length - 1 ]; - return keys[ keys.length - 1 ]; + } }; diff --git a/src/extras/animation/MorphAnimation.js b/src/extras/animation/MorphAnimation.js index 858eb135ae1ed0..c02243126f9bb2 100644 --- a/src/extras/animation/MorphAnimation.js +++ b/src/extras/animation/MorphAnimation.js @@ -50,19 +50,21 @@ THREE.MorphAnimation.prototype = { var interpolation = this.duration / this.frames; var frame = Math.floor( this.currentTime / interpolation ); + var influences = this.mesh.morphTargetInfluences; + if ( frame != this.currentFrame ) { - this.mesh.morphTargetInfluences[ this.lastFrame ] = 0; - this.mesh.morphTargetInfluences[ this.currentFrame ] = 1; - this.mesh.morphTargetInfluences[ frame ] = 0; + influences[ this.lastFrame ] = 0; + influences[ this.currentFrame ] = 1; + influences[ frame ] = 0; this.lastFrame = this.currentFrame; this.currentFrame = frame; } - this.mesh.morphTargetInfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation; - this.mesh.morphTargetInfluences[ this.lastFrame ] = 1 - this.mesh.morphTargetInfluences[ frame ]; + influences[ frame ] = ( this.currentTime % interpolation ) / interpolation; + influences[ this.lastFrame ] = 1 - influences[ frame ]; } diff --git a/src/extras/audio/Audio.js b/src/extras/audio/Audio.js index dee9d006f1d82f..1c922ba35c8018 100644 --- a/src/extras/audio/Audio.js +++ b/src/extras/audio/Audio.js @@ -10,6 +10,7 @@ THREE.Audio = function ( listener ) { this.context = listener.context; this.source = this.context.createBufferSource(); + this.source.onended = this.onEnded.bind(this); this.gain = this.context.createGain(); this.gain.connect( this.context.destination ); @@ -17,6 +18,11 @@ THREE.Audio = function ( listener ) { this.panner = this.context.createPanner(); this.panner.connect( this.gain ); + this.autoplay = false; + + this.startTime = 0; + this.isPlaying = false; + }; THREE.Audio.prototype = Object.create( THREE.Object3D.prototype ); @@ -34,8 +40,8 @@ THREE.Audio.prototype.load = function ( file ) { scope.context.decodeAudioData( this.response, function ( buffer ) { scope.source.buffer = buffer; - scope.source.connect( scope.panner ); - scope.source.start( 0 ); + + if( scope.autoplay ) scope.play(); } ); @@ -46,6 +52,49 @@ THREE.Audio.prototype.load = function ( file ) { }; +THREE.Audio.prototype.play = function () { + + if ( this.isPlaying === true ) { + + THREE.warn( 'THREE.Audio: Audio is already playing.' ); + return; + + } + + var source = this.context.createBufferSource(); + + source.buffer = this.source.buffer; + source.loop = this.source.loop; + source.onended = this.source.onended; + source.connect( this.panner ); + source.start( 0, this.startTime ); + + this.isPlaying = true; + + this.source = source; + +}; + +THREE.Audio.prototype.pause = function () { + + this.source.stop(); + this.startTime = this.context.currentTime; + +}; + +THREE.Audio.prototype.stop = function () { + + this.source.stop(); + this.startTime = 0; + +}; + +THREE.Audio.prototype.onEnded = function() { + + this.isPlaying = false; + +}; + THREE.Audio.prototype.setLoop = function ( value ) { this.source.loop = value; @@ -64,6 +113,12 @@ THREE.Audio.prototype.setRolloffFactor = function ( value ) { }; +THREE.Audio.prototype.setVolume = function ( value ) { + + this.gain.gain.value = value; + +}; + THREE.Audio.prototype.updateMatrixWorld = ( function () { var position = new THREE.Vector3(); diff --git a/src/extras/core/Curve.js b/src/extras/core/Curve.js index 04decdccd13363..a40e940f5b6840 100644 --- a/src/extras/core/Curve.js +++ b/src/extras/core/Curve.js @@ -43,7 +43,7 @@ THREE.Curve = function () { THREE.Curve.prototype.getPoint = function ( t ) { - console.log( "Warning, getPoint() not implemented!" ); + THREE.warn( "THREE.Curve: Warning, getPoint() not implemented!" ); return null; }; @@ -107,7 +107,7 @@ THREE.Curve.prototype.getLength = function () { THREE.Curve.prototype.getLengths = function ( divisions ) { - if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200; + if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200; if ( this.cacheArcLengths && ( this.cacheArcLengths.length == divisions + 1 ) @@ -182,12 +182,10 @@ THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { if ( comparison < 0 ) { low = i + 1; - continue; } else if ( comparison > 0 ) { high = i - 1; - continue; } else { @@ -214,17 +212,17 @@ THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { // we could get finer grain at lengths, or use simple interpolatation between two points var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; + var lengthAfter = arcLengths[ i + 1 ]; - var segmentLength = lengthAfter - lengthBefore; + var segmentLength = lengthAfter - lengthBefore; // determine where we are between the 'before' and 'after' points - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; // add that fractional amount to t - var t = ( i + segmentFraction ) / ( il -1 ); + var t = ( i + segmentFraction ) / ( il - 1 ); return t; @@ -283,8 +281,8 @@ THREE.Curve.Utils = { 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 * p1 * (1 - t) * (1 - t) - 6 * t * p1 * (1 - t) + + 6 * t * p2 * (1 - t) - 3 * t * t * p2 + 3 * t * t * p3; }, diff --git a/src/extras/core/CurvePath.js b/src/extras/core/CurvePath.js index b60feca5a89658..6fd68346ad9fc9 100644 --- a/src/extras/core/CurvePath.js +++ b/src/extras/core/CurvePath.js @@ -36,7 +36,7 @@ THREE.CurvePath.prototype.closePath = function() { // 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); + var endPoint = this.curves[this.curves.length - 1].getPoint(1); if (! startPoint.equals(endPoint)) { this.curves.push( new THREE.LineCurve(endPoint, startPoint) ); @@ -72,7 +72,6 @@ THREE.CurvePath.prototype.getPoint = function( t ) { return curve.getPointAt( u ); - break; } i ++; diff --git a/src/extras/core/Path.js b/src/extras/core/Path.js index 6e40375f96c2fd..a5ab82f82318cd 100644 --- a/src/extras/core/Path.js +++ b/src/extras/core/Path.js @@ -228,7 +228,7 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) { action = item.action; args = item.args; - switch( action ) { + switch ( action ) { case THREE.PathActions.MOVE_TO: @@ -375,7 +375,7 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) { //console.log(points); - break; + break; case THREE.PathActions.ELLIPSE: @@ -413,7 +413,7 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) { //console.log(points); - break; + break; } // end switch @@ -520,7 +520,7 @@ THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { // 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 ++ ) { + for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { var edgeLowPt = inPolygon[ p ]; var edgeHighPt = inPolygon[ q ]; @@ -633,7 +633,6 @@ THREE.Path.prototype.toShapes = function( isCCW, noHoles ) { 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]; diff --git a/src/extras/core/Shape.js b/src/extras/core/Shape.js index e97891637a2c12..de3bfbd4ce695b 100644 --- a/src/extras/core/Shape.js +++ b/src/extras/core/Shape.js @@ -173,16 +173,16 @@ THREE.Shape.Utils = { if ( perpSeg2 == 0 ) { if ( ( inExcludeAdjacentSegs ) && ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; - return [ inSeg1Pt1 ]; + return [ inSeg1Pt1 ]; } if ( perpSeg2 == limit ) { if ( ( inExcludeAdjacentSegs ) && ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; - return [ inSeg1Pt2 ]; + return [ inSeg1Pt2 ]; } // intersection at endpoint of segment#2? - if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ]; - if ( perpSeg1 == limit ) return [ inSeg2Pt2 ]; + if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ]; + if ( perpSeg1 == limit ) return [ inSeg2Pt2 ]; // return real intersection point var factorSeg1 = perpSeg2 / limit; @@ -200,17 +200,17 @@ THREE.Shape.Utils = { if ( seg1Pt && seg2Pt ) { if ( (inSeg1Pt1.x != inSeg2Pt1.x) || (inSeg1Pt1.y != inSeg2Pt1.y) ) return []; // they are distinct points - return [ inSeg1Pt1 ]; // they are the same point + 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 ]; + 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 ]; + return [ inSeg2Pt1 ]; } // they are collinear segments, which might overlap @@ -341,7 +341,7 @@ THREE.Shape.Utils = { // checks for intersections with shape edges var sIdx, nextIdx, intersection; for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) { - nextIdx = sIdx+1; nextIdx %= shape.length; + nextIdx = sIdx + 1; nextIdx %= shape.length; intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true ); if ( intersection.length > 0 ) return true; } @@ -358,7 +358,7 @@ THREE.Shape.Utils = { for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) { chkHole = holes[indepHoles[ihIdx]]; for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) { - nextIdx = hIdx+1; nextIdx %= chkHole.length; + nextIdx = hIdx + 1; nextIdx %= chkHole.length; intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true ); if ( intersection.length > 0 ) return true; } @@ -410,12 +410,12 @@ THREE.Shape.Utils = { if ( intersectsHoleEdge( shapePt, holePt ) ) continue; holeIndex = h2; - indepHoles.splice(h,1); + indepHoles.splice(h, 1); - tmpShape1 = shape.slice( 0, shapeIndex+1 ); + tmpShape1 = shape.slice( 0, shapeIndex + 1 ); tmpShape2 = shape.slice( shapeIndex ); tmpHole1 = hole.slice( holeIndex ); - tmpHole2 = hole.slice( 0, holeIndex+1 ); + tmpHole2 = hole.slice( 0, holeIndex + 1 ); shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); @@ -462,7 +462,7 @@ THREE.Shape.Utils = { if ( allPointsMap[ key ] !== undefined ) { - console.log( "Duplicate point", key ); + THREE.warn( "THREE.Shape: Duplicate point", key ); } diff --git a/src/extras/curves/SplineCurve.js b/src/extras/curves/SplineCurve.js index f79532f75ec63b..e695090fe9655a 100644 --- a/src/extras/curves/SplineCurve.js +++ b/src/extras/curves/SplineCurve.js @@ -21,8 +21,8 @@ THREE.SplineCurve.prototype.getPoint = function ( t ) { var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ] var point1 = points[ intPoint ] - var point2 = points[ intPoint > points.length - 2 ? points.length -1 : intPoint + 1 ] - var point3 = points[ intPoint > points.length - 3 ? points.length -1 : intPoint + 2 ] + var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ] + var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ] var vector = new THREE.Vector2(); diff --git a/src/extras/geometries/CubeGeometry.js b/src/extras/geometries/CubeGeometry.js index d2dff8ccf0126b..fdd0b1e5202508 100644 --- a/src/extras/geometries/CubeGeometry.js +++ b/src/extras/geometries/CubeGeometry.js @@ -5,7 +5,7 @@ THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { - console.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' ); + THREE.warn( 'THREE.CubeGeometry has been renamed to THREE.BoxGeometry.' ); return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ); }; diff --git a/src/extras/geometries/ExtrudeGeometry.js b/src/extras/geometries/ExtrudeGeometry.js index a5a5a9c9625cf3..59d9e58f470bbb 100644 --- a/src/extras/geometries/ExtrudeGeometry.js +++ b/src/extras/geometries/ExtrudeGeometry.js @@ -123,7 +123,6 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var ahole, h, hl; // looping of holes var scope = this; - var bevelPoints = []; var shapesOffset = this.vertices.length; @@ -163,7 +162,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var contour = vertices; // vertices has all points but contour has only points of circumference - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; @@ -174,7 +173,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { function scalePt2 ( pt, vec, size ) { - if ( ! vec ) console.log( "die" ); + if ( ! vec ) THREE.error( "THREE.ExtrudeGeometry: vec does not exist" ); return vec.clone().multiplyScalar( size ).add( pt ); @@ -182,14 +181,11 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var b, bs, t, z, vert, vlen = vertices.length, - face, flen = faces.length, - cont, clen = contour.length; + face, flen = faces.length; // Find directions for point movement - var RAD_TO_DEGREES = 180 / Math.PI; - function getBevelVec( inPt, inPrev, inNext ) { @@ -292,11 +288,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { // (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 ] ); + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); } @@ -314,7 +306,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { if ( k === il ) k = 0; // (j)---(i)---(k) - oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); } @@ -333,7 +325,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { z = bevelThickness * ( 1 - t ); //z = bevelThickness * t; - bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved + bs = bevelSize * ( Math.sin ( t * Math.PI / 2 ) ) ; // curved //bs = bevelSize * t ; // linear // contract shape @@ -433,7 +425,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { 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 ) ; + bs = bevelSize * Math.sin ( t * Math.PI / 2 ) ; // contract shape @@ -496,7 +488,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; - f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset ); + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); } @@ -543,7 +535,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { sidewalls( contour, layeroffset ); layeroffset += contour.length; - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; sidewalls( ahole, layeroffset ); @@ -560,7 +552,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var j, k; i = contour.length; - while ( --i >= 0 ) { + while ( -- i >= 0 ) { j = i; k = i - 1; @@ -605,7 +597,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var uvs = uvgen.generateTopUV( scope, a, b, c ); - scope.faceVertexUvs[ 0 ].push( uvs ); + scope.faceVertexUvs[ 0 ].push( uvs ); } @@ -616,13 +608,13 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { 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 ) ); + 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, a, b, c, d ); + var uvs = uvgen.generateSideWallUV( scope, a, b, c, d ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); - scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); + scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); } diff --git a/src/extras/geometries/ParametricGeometry.js b/src/extras/geometries/ParametricGeometry.js index 2297fc637dde97..83d0bf514b7aff 100644 --- a/src/extras/geometries/ParametricGeometry.js +++ b/src/extras/geometries/ParametricGeometry.js @@ -23,10 +23,9 @@ THREE.ParametricGeometry = function ( func, slices, stacks ) { var faces = this.faces; var uvs = this.faceVertexUvs[ 0 ]; - var i, il, j, p; + var i, j, p; var u, v; - var stackCount = stacks + 1; var sliceCount = slices + 1; for ( i = 0; i <= stacks; i ++ ) { diff --git a/src/extras/geometries/PolyhedronGeometry.js b/src/extras/geometries/PolyhedronGeometry.js index 32cdd56898c8ad..4affb75b344543 100644 --- a/src/extras/geometries/PolyhedronGeometry.js +++ b/src/extras/geometries/PolyhedronGeometry.js @@ -28,7 +28,7 @@ THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { } - var midpoints = [], p = this.vertices; + var p = this.vertices; var faces = []; @@ -136,7 +136,6 @@ THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) { 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 ] ); diff --git a/src/extras/geometries/ShapeGeometry.js b/src/extras/geometries/ShapeGeometry.js index d3ac6ad9b84f21..1cd1c0111e02f7 100644 --- a/src/extras/geometries/ShapeGeometry.js +++ b/src/extras/geometries/ShapeGeometry.js @@ -59,7 +59,7 @@ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { // - var i, l, hole, s; + var i, l, hole; var shapesOffset = this.vertices.length; var shapePoints = shape.extractPoints( curveSegments ); @@ -108,7 +108,6 @@ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { var vert, vlen = vertices.length; var face, flen = faces.length; - var cont, clen = contour.length; for ( i = 0; i < vlen; i ++ ) { diff --git a/src/extras/geometries/TubeGeometry.js b/src/extras/geometries/TubeGeometry.js index 581c9d541d223a..4b11c56d252e40 100644 --- a/src/extras/geometries/TubeGeometry.js +++ b/src/extras/geometries/TubeGeometry.js @@ -42,8 +42,6 @@ THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed, numpoints = segments + 1, - x, y, z, - tx, ty, tz, u, v, r, cx, cy, @@ -154,9 +152,7 @@ THREE.TubeGeometry.SinusoidalTaper = function ( u ) { // 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(), + var normal = new THREE.Vector3(), tangents = [], normals = [], @@ -171,7 +167,7 @@ THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { smallest, tx, ty, tz, - i, u, v; + i, u; // expose internals @@ -252,17 +248,17 @@ THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { for ( i = 1; i < numpoints; i ++ ) { - normals[ i ] = normals[ i-1 ].clone(); + normals[ i ] = normals[ i - 1 ].clone(); - binormals[ i ] = binormals[ i-1 ].clone(); + binormals[ i ] = binormals[ i - 1 ].clone(); - vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); + 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 + 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 ) ); @@ -277,10 +273,10 @@ THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) { if ( closed ) { - theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), - 1, 1 ) ); + 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 ) { + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints - 1 ] ) ) > 0 ) { theta = - theta; diff --git a/src/extras/helpers/EdgesHelper.js b/src/extras/helpers/EdgesHelper.js index a5925655ee2957..8356d21ea5add8 100644 --- a/src/extras/helpers/EdgesHelper.js +++ b/src/extras/helpers/EdgesHelper.js @@ -1,10 +1,19 @@ /** * @author WestLangley / http://github.com/WestLangley + * @param object THREE.Mesh whose geometry will be used + * @param hex line color + * @param thresholdAngle the minimim angle (in degrees), + * between the face normals of adjacent faces, + * that is required to render an edge. A value of 10 means + * an edge is only rendered if the angle is at least 10 degrees. */ -THREE.EdgesHelper = function ( object, hex ) { +THREE.EdgesHelper = function ( object, hex, thresholdAngle ) { var color = ( hex !== undefined ) ? hex : 0xffffff; + thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; + + var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) ); var edge = [ 0, 0 ], hash = {}; var sortFunction = function ( a, b ) { return a - b }; @@ -12,7 +21,18 @@ THREE.EdgesHelper = function ( object, hex ) { var keys = [ 'a', 'b', 'c' ]; var geometry = new THREE.BufferGeometry(); - var geometry2 = object.geometry.clone(); + var geometry2; + + if ( object.geometry instanceof THREE.BufferGeometry ) { + + geometry2 = new THREE.Geometry(); + geometry2.fromBufferGeometry( object.geometry ); + + } else { + + geometry2 = object.geometry.clone(); + + } geometry2.mergeVertices(); geometry2.computeFaceNormals(); @@ -56,7 +76,7 @@ THREE.EdgesHelper = function ( object, hex ) { var h = hash[ key ]; - if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) < 0.9999 ) { // hardwired const OK + if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) { var vertex = vertices[ h.vert1 ]; coords[ index ++ ] = vertex.x; diff --git a/src/extras/helpers/HemisphereLightHelper.js b/src/extras/helpers/HemisphereLightHelper.js index 5273af8300013f..469708f5cb1702 100644 --- a/src/extras/helpers/HemisphereLightHelper.js +++ b/src/extras/helpers/HemisphereLightHelper.js @@ -3,7 +3,7 @@ * @author mrdoob / http://mrdoob.com/ */ -THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { +THREE.HemisphereLightHelper = function ( light, sphereSize ) { THREE.Object3D.call( this ); diff --git a/src/extras/helpers/VertexNormalsHelper.js b/src/extras/helpers/VertexNormalsHelper.js index f8c8551773e321..64481b870fa718 100644 --- a/src/extras/helpers/VertexNormalsHelper.js +++ b/src/extras/helpers/VertexNormalsHelper.js @@ -15,8 +15,6 @@ THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { 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 ++ ) { diff --git a/src/extras/helpers/VertexTangentsHelper.js b/src/extras/helpers/VertexTangentsHelper.js index 0403963b0a82d8..4852f9c457299c 100644 --- a/src/extras/helpers/VertexTangentsHelper.js +++ b/src/extras/helpers/VertexTangentsHelper.js @@ -15,8 +15,6 @@ THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { 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 ++ ) { diff --git a/src/extras/objects/MorphBlendMesh.js b/src/extras/objects/MorphBlendMesh.js index 3c04a7aa64bd75..f40ac4becab6db 100644 --- a/src/extras/objects/MorphBlendMesh.js +++ b/src/extras/objects/MorphBlendMesh.js @@ -27,7 +27,7 @@ THREE.MorphBlendMesh = function( geometry, material ) { }; THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); -THREE.MorphBlendMesh.prototype.constructor = THREE.MorphBlendMesh; +THREE.MorphBlendMesh.prototype.constructor = THREE.MorphBlendMesh; THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { @@ -76,7 +76,6 @@ THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { if ( chunks && chunks.length > 1 ) { var name = chunks[ 1 ]; - var num = chunks[ 2 ]; if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity }; @@ -221,7 +220,7 @@ THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { } else { - console.warn( "animation[" + name + "] undefined" ); + THREE.warn( "THREE.MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" ); } diff --git a/src/lights/DirectionalLight.js b/src/lights/DirectionalLight.js index 20c38e095c45d0..f78192e8f106b3 100644 --- a/src/lights/DirectionalLight.js +++ b/src/lights/DirectionalLight.js @@ -47,7 +47,7 @@ THREE.DirectionalLight = function ( color, intensity ) { this.shadowCascadeHeight = [ 512, 512, 512 ]; this.shadowCascadeNearZ = [ - 1.000, 0.990, 0.998 ]; - this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; + this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; this.shadowCascadeArray = []; diff --git a/src/lights/PointLight.js b/src/lights/PointLight.js index c81d689c0c9a55..15e309ac9d3d11 100644 --- a/src/lights/PointLight.js +++ b/src/lights/PointLight.js @@ -2,7 +2,7 @@ * @author mrdoob / http://mrdoob.com/ */ -THREE.PointLight = function ( color, intensity, distance ) { +THREE.PointLight = function ( color, intensity, distance, decay ) { THREE.Light.call( this, color ); @@ -10,6 +10,7 @@ THREE.PointLight = function ( color, intensity, distance ) { this.intensity = ( intensity !== undefined ) ? intensity : 1; this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. }; @@ -24,6 +25,7 @@ THREE.PointLight.prototype.clone = function () { light.intensity = this.intensity; light.distance = this.distance; + light.decay = this.decay; return light; diff --git a/src/lights/SpotLight.js b/src/lights/SpotLight.js index cbc82bde5988ec..50384adb6bb141 100644 --- a/src/lights/SpotLight.js +++ b/src/lights/SpotLight.js @@ -2,7 +2,7 @@ * @author alteredq / http://alteredqualia.com/ */ -THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { +THREE.SpotLight = function ( color, intensity, distance, angle, exponent, decay ) { THREE.Light.call( this, color ); @@ -15,6 +15,7 @@ THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { this.distance = ( distance !== undefined ) ? distance : 0; this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; this.exponent = ( exponent !== undefined ) ? exponent : 10; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. this.castShadow = false; this.onlyShadow = false; @@ -57,6 +58,7 @@ THREE.SpotLight.prototype.clone = function () { light.distance = this.distance; light.angle = this.angle; light.exponent = this.exponent; + light.decay = this.decay; light.castShadow = this.castShadow; light.onlyShadow = this.onlyShadow; diff --git a/src/loaders/BinaryTextureLoader.js b/src/loaders/BinaryTextureLoader.js index b9266f57a6a1e8..913a5e318f49cb 100644 --- a/src/loaders/BinaryTextureLoader.js +++ b/src/loaders/BinaryTextureLoader.js @@ -34,7 +34,7 @@ THREE.BinaryTextureLoader.prototype = { texture.image = texData.image; - } else if ( undefined !== texData.data ){ + } else if ( undefined !== texData.data ) { texture.image.width = texData.width; texture.image.height = texData.height; diff --git a/src/loaders/BufferGeometryLoader.js b/src/loaders/BufferGeometryLoader.js index 7dc26fb25b4091..a7333e94cdde03 100644 --- a/src/loaders/BufferGeometryLoader.js +++ b/src/loaders/BufferGeometryLoader.js @@ -36,7 +36,7 @@ THREE.BufferGeometryLoader.prototype = { var geometry = new THREE.BufferGeometry(); - var attributes = json.attributes; + var attributes = json.data.attributes; for ( var key in attributes ) { @@ -47,7 +47,7 @@ THREE.BufferGeometryLoader.prototype = { } - var offsets = json.offsets; + var offsets = json.data.offsets; if ( offsets !== undefined ) { @@ -55,7 +55,7 @@ THREE.BufferGeometryLoader.prototype = { } - var boundingSphere = json.boundingSphere; + var boundingSphere = json.data.boundingSphere; if ( boundingSphere !== undefined ) { diff --git a/src/loaders/Cache.js b/src/loaders/Cache.js index 6859ae01b62243..87227cba054793 100644 --- a/src/loaders/Cache.js +++ b/src/loaders/Cache.js @@ -2,15 +2,9 @@ * @author mrdoob / http://mrdoob.com/ */ -THREE.Cache = function () { +THREE.Cache = { - this.files = {}; - -}; - -THREE.Cache.prototype = { - - constructor: THREE.Cache, + files: {}, add: function ( key, file ) { diff --git a/src/loaders/CompressedTextureLoader.js b/src/loaders/CompressedTextureLoader.js index 3ef59092fb62eb..6eece366653484 100644 --- a/src/loaders/CompressedTextureLoader.js +++ b/src/loaders/CompressedTextureLoader.js @@ -49,7 +49,7 @@ THREE.CompressedTextureLoader.prototype = { if ( loaded === 6 ) { - if (texDatas.mipmapCount == 1) + if (texDatas.mipmapCount == 1) texture.minFilter = THREE.LinearFilter; texture.format = texDatas.format; diff --git a/src/loaders/ImageLoader.js b/src/loaders/ImageLoader.js index d5ef39ca75aad7..a73a75c46b84f9 100644 --- a/src/loaders/ImageLoader.js +++ b/src/loaders/ImageLoader.js @@ -4,7 +4,6 @@ THREE.ImageLoader = function ( manager ) { - this.cache = new THREE.Cache(); this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; @@ -17,7 +16,7 @@ THREE.ImageLoader.prototype = { var scope = this; - var cached = scope.cache.get( url ); + var cached = THREE.Cache.get( url ); if ( cached !== undefined ) { @@ -28,18 +27,15 @@ THREE.ImageLoader.prototype = { var image = document.createElement( 'img' ); - if ( onLoad !== undefined ) { + image.addEventListener( 'load', function ( event ) { - image.addEventListener( 'load', function ( event ) { + THREE.Cache.add( url, this ); - scope.cache.add( url, this ); + if ( onLoad ) onLoad( this ); + + scope.manager.itemEnd( url ); - onLoad( this ); - scope.manager.itemEnd( url ); - - }, false ); - - } + }, false ); if ( onProgress !== undefined ) { diff --git a/src/loaders/JSONLoader.js b/src/loaders/JSONLoader.js index 214f946c685955..9e6832db2b52db 100644 --- a/src/loaders/JSONLoader.js +++ b/src/loaders/JSONLoader.js @@ -16,8 +16,6 @@ THREE.JSONLoader.prototype.constructor = THREE.JSONLoader; 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 ); @@ -42,18 +40,23 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex if ( xhr.responseText ) { var json = JSON.parse( xhr.responseText ); + var metadata = json.metadata; - if ( json.metadata !== undefined && json.metadata.version >= 4 ) { + if ( metadata !== undefined ) { - console.error( 'THREE.JSONLoader: "' + url + '" should be loaded with THREE.ObjectLoader instead.' ); - return; + if ( metadata.type === 'object' ) { - } + THREE.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); + return; + + } + + if ( metadata.type === 'scene' ) { - if ( json.metadata !== undefined && json.metadata.type === 'scene' ) { + THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.' ); + return; - console.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); - return; + } } @@ -62,7 +65,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.error( 'THREE.JSONLoader: ' + url + ' seems to be unreachable or the file is empty.' ); } @@ -74,7 +77,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex } else { - console.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); + THREE.error( 'THREE.JSONLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' ); } @@ -112,8 +115,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { - var scope = this, - geometry = new THREE.Geometry(), + var geometry = new THREE.Geometry(), scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; parseModel( scale ); @@ -145,7 +147,7 @@ THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor, - vertex, face, faceA, faceB, color, hex, normal, + vertex, face, faceA, faceB, hex, normal, uvLayer, uv, u, v, @@ -461,7 +463,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.warn( 'THREE.JSONLoader: When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); } diff --git a/src/loaders/Loader.js b/src/loaders/Loader.js index 6fa430e726c742..c6b0e62182c1af 100644 --- a/src/loaders/Loader.js +++ b/src/loaders/Loader.js @@ -226,12 +226,18 @@ THREE.Loader.prototype = { } - if ( m.transparent !== undefined || m.opacity < 1.0 ) { + if ( m.transparent !== undefined ) { mpars.transparent = m.transparent; } + if ( m.opacity !== undefined && m.opacity < 1.0 ) { + + mpars.transparent = true; + + } + if ( m.depthTest !== undefined ) { mpars.depthTest = m.depthTest; @@ -308,14 +314,14 @@ THREE.Loader.prototype = { // modifiers - if ( m.transparency ) { + if ( m.transparency !== undefined ) { - console.warn( 'transparency has been renamed to opacity' ); - mpars.opacity = m.transparency; + console.warn( 'THREE.Loader: transparency has been renamed to opacity' ); + m.opacity = m.transparency; } - if ( m.opacity ) { + if ( m.opacity !== undefined ) { mpars.opacity = m.opacity; diff --git a/src/loaders/MaterialLoader.js b/src/loaders/MaterialLoader.js index dadd082c0935f7..a8e7f86aebf103 100644 --- a/src/loaders/MaterialLoader.js +++ b/src/loaders/MaterialLoader.js @@ -51,6 +51,10 @@ THREE.MaterialLoader.prototype = { if ( json.transparent !== undefined ) material.transparent = json.transparent; if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + // for PointCloudMaterial + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + if ( json.materials !== undefined ) { for ( var i = 0, l = json.materials.length; i < l; i ++ ) { diff --git a/src/loaders/ObjectLoader.js b/src/loaders/ObjectLoader.js index 741dd72575baca..4299026b317867 100644 --- a/src/loaders/ObjectLoader.js +++ b/src/loaders/ObjectLoader.js @@ -5,6 +5,7 @@ THREE.ObjectLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.texturePath = ''; }; @@ -14,30 +15,55 @@ THREE.ObjectLoader.prototype = { load: function ( url, onLoad, onProgress, onError ) { + if ( this.texturePath === '' ) { + + this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); + + } + 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 ) ) ); + scope.parse( JSON.parse( text ), onLoad ); }, onProgress, onError ); }, + setTexturePath: function ( value ) { + + this.texturePath = value; + + }, + setCrossOrigin: function ( value ) { this.crossOrigin = value; }, - parse: function ( json ) { + parse: function ( json, onLoad ) { var geometries = this.parseGeometries( json.geometries ); - var materials = this.parseMaterials( json.materials ); + + var images = this.parseImages( json.images, function () { + + if ( onLoad !== undefined ) onLoad( object ); + + } ); + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); var object = this.parseObject( json.object, geometries, materials ); + if ( json.images === undefined || json.images.length === 0 ) { + + if ( onLoad !== undefined ) onLoad( object ); + + } + return object; }, @@ -59,8 +85,9 @@ THREE.ObjectLoader.prototype = { switch ( data.type ) { case 'PlaneGeometry': + case 'PlaneBufferGeometry': - geometry = new THREE.PlaneGeometry( + geometry = new THREE[ data.type ]( data.width, data.height, data.widthSegments, @@ -156,7 +183,7 @@ THREE.ObjectLoader.prototype = { case 'BufferGeometry': - geometry = bufferGeometryLoader.parse( data.data ); + geometry = bufferGeometryLoader.parse( data ); break; @@ -182,12 +209,24 @@ THREE.ObjectLoader.prototype = { }, - parseMaterials: function ( json ) { + parseMaterials: function ( json, textures ) { var materials = {}; if ( json !== undefined ) { + var getTexture = function ( name ) { + + if ( textures[ name ] === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: Undefined texture', name ); + + } + + return textures[ name ]; + + }; + var loader = new THREE.MaterialLoader(); for ( var i = 0, l = json.length; i < l; i ++ ) { @@ -199,6 +238,54 @@ THREE.ObjectLoader.prototype = { if ( data.name !== undefined ) material.name = data.name; + if ( data.map !== undefined ) { + + material.map = getTexture( data.map ); + + } + + if ( data.bumpMap !== undefined ) { + + material.bumpMap = getTexture( data.bumpMap ); + if ( data.bumpScale ) { + material.bumpScale = new THREE.Vector2( data.bumpScale, data.bumpScale ); + } + + } + + if ( data.alphaMap !== undefined ) { + + material.alphaMap = getTexture( data.alphaMap ); + + } + + if ( data.envMap !== undefined ) { + + material.envMap = getTexture( data.envMap ); + + } + + if ( data.normalMap !== undefined ) { + + material.normalMap = getTexture( data.normalMap ); + if ( data.normalScale ) { + material.normalScale = new THREE.Vector2( data.normalScale, data.normalScale ); + } + + } + + if ( data.lightMap !== undefined ) { + + material.lightMap = getTexture( data.lightMap ); + + } + + if ( data.specularMap !== undefined ) { + + material.specularMap = getTexture( data.specularMap ); + + } + materials[ data.uuid ] = material; } @@ -209,6 +296,94 @@ THREE.ObjectLoader.prototype = { }, + parseImages: function ( json, onLoad ) { + + var scope = this; + var images = {}; + + if ( json !== undefined && json.length > 0 ) { + + var manager = new THREE.LoadingManager( onLoad ); + + var loader = new THREE.ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); + + var loadImage = function ( url ) { + + scope.manager.itemStart( url ); + + return loader.load( url, function () { + + scope.manager.itemEnd( url ); + + } ); + + }; + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var image = json[ i ]; + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; + + images[ image.uuid ] = loadImage( path ); + + } + + } + + return images; + + }, + + parseTextures: function ( json, images ) { + + var textures = {}; + + if ( json !== undefined ) { + + for ( var i = 0, l = json.length; i < l; i ++ ) { + + var data = json[ i ]; + + if ( data.image === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: No "image" speficied for', data.uuid ); + + } + + if ( images[ data.image ] === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + + } + + var texture = new THREE.Texture( images[ data.image ] ); + texture.needsUpdate = true; + + texture.uuid = data.uuid; + + if ( data.name !== undefined ) texture.name = data.name; + if ( data.repeat !== undefined ) texture.repeat = new THREE.Vector2( data.repeat[ 0 ], data.repeat[ 1 ] ); + if ( data.minFilter !== undefined ) texture.minFilter = THREE[ data.minFilter ]; + if ( data.magFilter !== undefined ) texture.magFilter = THREE[ data.magFilter ]; + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + if ( data.wrap instanceof Array ) { + + texture.wrapS = THREE[ data.wrap[ 0 ] ]; + texture.wrapT = THREE[ data.wrap[ 1 ] ]; + + } + + textures[ data.uuid ] = texture; + + } + + } + + return textures; + + }, + parseObject: function () { var matrix = new THREE.Matrix4(); @@ -217,6 +392,30 @@ THREE.ObjectLoader.prototype = { var object; + var getGeometry = function ( name ) { + + if ( geometries[ name ] === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + + } + + return geometries[ name ]; + + }; + + var getMaterial = function ( name ) { + + if ( materials[ name ] === undefined ) { + + THREE.warn( 'THREE.ObjectLoader: Undefined material', name ); + + } + + return materials[ name ]; + + }; + switch ( data.type ) { case 'Scene': @@ -251,13 +450,13 @@ 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 ); 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 ); break; @@ -269,57 +468,25 @@ THREE.ObjectLoader.prototype = { case 'Mesh': - var geometry = geometries[ data.geometry ]; - var material = materials[ data.material ]; - - if ( geometry === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined geometry', data.geometry ); - - } - - if ( material === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', data.material ); - - } - - object = new THREE.Mesh( geometry, material ); + object = new THREE.Mesh( getGeometry( data.geometry ), getMaterial( data.material ) ); break; case 'Line': - var geometry = geometries[ data.geometry ]; - var material = materials[ data.material ]; - - if ( geometry === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined geometry', data.geometry ); - - } + object = new THREE.Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - if ( material === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', data.material ); + break; - } + case 'PointCloud': - object = new THREE.Line( geometry, material ); + object = new THREE.PointCloud( getGeometry( data.geometry ), getMaterial( data.material ) ); break; case 'Sprite': - var material = materials[ data.material ]; - - if ( material === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', data.material ); - - } - - object = new THREE.Sprite( material ); + object = new THREE.Sprite( getMaterial( data.material ) ); break; diff --git a/src/loaders/XHRLoader.js b/src/loaders/XHRLoader.js index 0440d45a0c956d..1080719a7b52b4 100644 --- a/src/loaders/XHRLoader.js +++ b/src/loaders/XHRLoader.js @@ -4,7 +4,6 @@ THREE.XHRLoader = function ( manager ) { - this.cache = new THREE.Cache(); this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; @@ -17,7 +16,7 @@ THREE.XHRLoader.prototype = { var scope = this; - var cached = scope.cache.get( url ); + var cached = THREE.Cache.get( url ); if ( cached !== undefined ) { @@ -31,7 +30,7 @@ THREE.XHRLoader.prototype = { request.addEventListener( 'load', function ( event ) { - scope.cache.add( url, this.response ); + THREE.Cache.add( url, this.response ); if ( onLoad ) onLoad( this.response ); diff --git a/src/materials/Material.js b/src/materials/Material.js index 6ebf17702299c8..216c07b966a682 100644 --- a/src/materials/Material.js +++ b/src/materials/Material.js @@ -29,6 +29,8 @@ THREE.Material = function () { this.depthTest = true; this.depthWrite = true; + this.colorWrite = true; + this.polygonOffset = false; this.polygonOffsetFactor = 0; this.polygonOffsetUnits = 0; @@ -39,7 +41,7 @@ THREE.Material = function () { this.visible = true; - this.needsUpdate = true; + this._needsUpdate = true; }; @@ -47,6 +49,20 @@ THREE.Material.prototype = { constructor: THREE.Material, + get needsUpdate () { + + return this._needsUpdate; + + }, + + set needsUpdate ( value ) { + + if ( value === true ) this.update(); + + this._needsUpdate = value; + + }, + setValues: function ( values ) { if ( values === undefined ) return; @@ -57,7 +73,7 @@ THREE.Material.prototype = { if ( newValue === undefined ) { - console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); + THREE.warn( "THREE.Material: '" + key + "' parameter is undefined." ); continue; } @@ -117,6 +133,7 @@ THREE.Material.prototype = { output.color = this.color.getHex(); output.emissive = this.emissive.getHex(); if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; if ( this.side !== THREE.FrontSide ) output.side = this.side; @@ -127,12 +144,12 @@ THREE.Material.prototype = { output.specular = this.specular.getHex(); output.shininess = this.shininess; if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.shading !== THREE.SmoothShading ) output.shading = this.shading; if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; if ( this.side !== THREE.FrontSide ) output.side = this.side; } else if ( this instanceof THREE.MeshNormalMaterial ) { - if ( this.shading !== THREE.FlatShading ) output.shading = this.shading; if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; if ( this.side !== THREE.FrontSide ) output.side = this.side; @@ -141,6 +158,15 @@ THREE.Material.prototype = { if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; if ( this.side !== THREE.FrontSide ) output.side = this.side; + } else if ( this instanceof THREE.PointCloudMaterial ) { + + output.size = this.size; + output.sizeAttenuation = this.sizeAttenuation; + output.color = this.color.getHex(); + + if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors; + if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending; + } else if ( this instanceof THREE.ShaderMaterial ) { output.uniforms = this.uniforms; @@ -198,6 +224,12 @@ THREE.Material.prototype = { }, + update: function () { + + this.dispatchEvent( { type: 'update' } ); + + }, + dispose: function () { this.dispatchEvent( { type: 'dispose' } ); diff --git a/src/materials/MeshNormalMaterial.js b/src/materials/MeshNormalMaterial.js index 1839fc70394877..1895f002b59f5b 100644 --- a/src/materials/MeshNormalMaterial.js +++ b/src/materials/MeshNormalMaterial.js @@ -20,8 +20,6 @@ THREE.MeshNormalMaterial = function ( parameters ) { this.type = 'MeshNormalMaterial'; - this.shading = THREE.FlatShading; - this.wireframe = false; this.wireframeLinewidth = 1; @@ -40,8 +38,6 @@ THREE.MeshNormalMaterial.prototype.clone = function () { THREE.Material.prototype.clone.call( this, material ); - material.shading = this.shading; - material.wireframe = this.wireframe; material.wireframeLinewidth = this.wireframeLinewidth; diff --git a/src/materials/PointCloudMaterial.js b/src/materials/PointCloudMaterial.js index 0a3891092b9d84..69f53df8e34bc4 100644 --- a/src/materials/PointCloudMaterial.js +++ b/src/materials/PointCloudMaterial.js @@ -69,14 +69,14 @@ THREE.PointCloudMaterial.prototype.clone = function () { THREE.ParticleBasicMaterial = function ( parameters ) { - console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); + THREE.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); return new THREE.PointCloudMaterial( parameters ); }; THREE.ParticleSystemMaterial = function ( parameters ) { - console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' ); + THREE.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' ); return new THREE.PointCloudMaterial( parameters ); }; diff --git a/src/math/Color.js b/src/math/Color.js index d00573d1908cf2..eb98b4585597bb 100644 --- a/src/math/Color.js +++ b/src/math/Color.js @@ -173,21 +173,27 @@ THREE.Color.prototype = { }, - copyGammaToLinear: function ( color ) { + copyGammaToLinear: function ( color, gammaFactor ) { - this.r = color.r * color.r; - this.g = color.g * color.g; - this.b = color.b * color.b; + if ( gammaFactor === undefined ) gammaFactor = 2.0; + + this.r = Math.pow( color.r, gammaFactor ); + this.g = Math.pow( color.g, gammaFactor ); + this.b = Math.pow( color.b, gammaFactor ); return this; }, - copyLinearToGamma: function ( color ) { + copyLinearToGamma: function ( color, gammaFactor ) { + + if ( gammaFactor === undefined ) gammaFactor = 2.0; - this.r = Math.sqrt( color.r ); - this.g = Math.sqrt( color.g ); - this.b = Math.sqrt( color.b ); + var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; + + this.r = Math.pow( color.r, safeInverse ); + this.g = Math.pow( color.g, safeInverse ); + this.b = Math.pow( color.b, safeInverse ); return this; @@ -366,10 +372,16 @@ THREE.Color.prototype = { }, - toArray: function () { + toArray: function ( array, offset ) { + + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; - return [ this.r, this.g, this.b ]; + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; + return array; }, clone: function () { diff --git a/src/math/Euler.js b/src/math/Euler.js index ee323f431374d9..70a54b20c636c1 100644 --- a/src/math/Euler.js +++ b/src/math/Euler.js @@ -212,7 +212,7 @@ THREE.Euler.prototype = { } else { - console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) + THREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ) } @@ -280,10 +280,17 @@ THREE.Euler.prototype = { }, - toArray: function () { + toArray: function ( array, offset ) { - return [ this._x, this._y, this._z, this._order ]; + if ( array === undefined ) array = []; + if ( offset === undefined ) offset = 0; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; + + return array; }, toVector3: function ( optionalResult ) { diff --git a/src/math/Math.js b/src/math/Math.js index 0af95b4de05cde..40a9bf9c672ff7 100644 --- a/src/math/Math.js +++ b/src/math/Math.js @@ -150,6 +150,20 @@ THREE.Math = { return ( value & ( value - 1 ) ) === 0 && value !== 0; + }, + + nextPowerOfTwo: function ( value ) { + + value --; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + value ++; + + return value; + } }; diff --git a/src/math/Matrix3.js b/src/math/Matrix3.js index 6dc582649f1379..f62ca7036d67aa 100644 --- a/src/math/Matrix3.js +++ b/src/math/Matrix3.js @@ -16,7 +16,7 @@ THREE.Matrix3 = function () { if ( arguments.length > 0 ) { - console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); + THREE.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); } @@ -70,14 +70,14 @@ THREE.Matrix3.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); return vector.applyMatrix3( this ); }, multiplyVector3Array: function ( a ) { - console.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + THREE.warn( 'THREE.Matrix3: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); return this.applyToVector3Array( a ); }, @@ -91,7 +91,7 @@ THREE.Matrix3.prototype = { if ( offset === undefined ) offset = 0; if ( length === undefined ) length = array.length; - for ( var i = 0, j = offset, il; i < length; i += 3, j += 3 ) { + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { v1.x = array[ j ]; v1.y = array[ j + 1 ]; @@ -167,7 +167,7 @@ THREE.Matrix3.prototype = { } else { - console.warn( msg ); + THREE.warn( msg ); } diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index a62e7271e1dd3c..73975d92119234 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -24,7 +24,7 @@ THREE.Matrix4 = function () { if ( arguments.length > 0 ) { - console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); + THREE.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); } @@ -72,7 +72,7 @@ THREE.Matrix4.prototype = { extractPosition: function ( m ) { - console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); + THREE.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); return this.copyPosition( m ); }, @@ -92,15 +92,15 @@ THREE.Matrix4.prototype = { extractBasis: function ( xAxis, yAxis, zAxis ) { - var te = this.elements; + 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; + return this; - }, + }, makeBasis: function ( xAxis, yAxis, zAxis ) { @@ -111,7 +111,7 @@ THREE.Matrix4.prototype = { 0, 0, 0, 1 ); - return this; + return this; }, @@ -150,7 +150,7 @@ THREE.Matrix4.prototype = { if ( euler instanceof THREE.Euler === false ) { - console.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); + THREE.error( 'THREE.Matrix: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } @@ -276,7 +276,7 @@ THREE.Matrix4.prototype = { setRotationFromQuaternion: function ( q ) { - console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); + THREE.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); return this.makeRotationFromQuaternion( q ); @@ -363,7 +363,7 @@ THREE.Matrix4.prototype = { if ( n !== undefined ) { - console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); return this.multiplyMatrices( m, n ); } @@ -442,21 +442,21 @@ THREE.Matrix4.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); return vector.applyProjection( this ); }, multiplyVector4: function ( vector ) { - console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, multiplyVector3Array: function ( a ) { - console.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); + THREE.warn( 'THREE.Matrix4: .multiplyVector3Array() has been renamed. Use matrix.applyToVector3Array( array ) instead.' ); return this.applyToVector3Array( a ); }, @@ -470,7 +470,7 @@ THREE.Matrix4.prototype = { if ( offset === undefined ) offset = 0; if ( length === undefined ) length = array.length; - for ( var i = 0, j = offset, il; i < length; i += 3, j += 3 ) { + for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) { v1.x = array[ j ]; v1.y = array[ j + 1 ]; @@ -492,7 +492,7 @@ THREE.Matrix4.prototype = { rotateAxis: function ( v ) { - console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); v.transformDirection( this ); @@ -500,7 +500,7 @@ THREE.Matrix4.prototype = { crossVector: function ( vector ) { - console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, @@ -606,7 +606,7 @@ THREE.Matrix4.prototype = { return function () { - console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + THREE.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); var te = this.elements; return v1.set( te[ 12 ], te[ 13 ], te[ 14 ] ); @@ -659,7 +659,7 @@ THREE.Matrix4.prototype = { if ( det == 0 ) { - var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0"; + var msg = "THREE.Matrix4.getInverse(): can't invert matrix, determinant is 0"; if ( throwOnInvertible || false ) { @@ -667,7 +667,7 @@ THREE.Matrix4.prototype = { } else { - console.warn( msg ); + THREE.warn( msg ); } @@ -684,31 +684,31 @@ THREE.Matrix4.prototype = { translate: function ( v ) { - console.warn( 'THREE.Matrix4: .translate() has been removed.' ); + THREE.error( 'THREE.Matrix4: .translate() has been removed.' ); }, rotateX: function ( angle ) { - console.warn( 'THREE.Matrix4: .rotateX() has been removed.' ); + THREE.error( 'THREE.Matrix4: .rotateX() has been removed.' ); }, rotateY: function ( angle ) { - console.warn( 'THREE.Matrix4: .rotateY() has been removed.' ); + THREE.error( 'THREE.Matrix4: .rotateY() has been removed.' ); }, rotateZ: function ( angle ) { - console.warn( 'THREE.Matrix4: .rotateZ() has been removed.' ); + THREE.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); }, rotateByAxis: function ( axis, angle ) { - console.warn( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); + THREE.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); }, diff --git a/src/math/Quaternion.js b/src/math/Quaternion.js index 2ac5218aa9bb2b..861e99e0ddca70 100644 --- a/src/math/Quaternion.js +++ b/src/math/Quaternion.js @@ -363,7 +363,7 @@ THREE.Quaternion.prototype = { if ( p !== undefined ) { - console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + THREE.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); return this.multiplyQuaternions( q, p ); } @@ -392,7 +392,7 @@ THREE.Quaternion.prototype = { multiplyVector3: function ( vector ) { - console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); + THREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); return vector.applyQuaternion( this ); }, diff --git a/src/math/Ray.js b/src/math/Ray.js index 8ebc86373faf21..253de466c6c076 100644 --- a/src/math/Ray.js +++ b/src/math/Ray.js @@ -345,7 +345,7 @@ THREE.Ray.prototype = { }(), - intersectBox: function ( box , optionalTarget ) { + intersectBox: function ( box, optionalTarget ) { // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ diff --git a/src/math/Sphere.js b/src/math/Sphere.js index cadacfe746749b..52cff009c94fee 100644 --- a/src/math/Sphere.js +++ b/src/math/Sphere.js @@ -26,7 +26,7 @@ THREE.Sphere.prototype = { var box = new THREE.Box3(); - return function ( points, optionalCenter ) { + return function ( points, optionalCenter ) { var center = this.center; @@ -52,7 +52,7 @@ THREE.Sphere.prototype = { return this; - }; + }; }(), diff --git a/src/math/Spline.js b/src/math/Spline.js index 6ff994e5b6b362..4ec2d7fb690d30 100644 --- a/src/math/Spline.js +++ b/src/math/Spline.js @@ -125,7 +125,7 @@ THREE.Spline = function ( points ) { var i, j, index, indexCurrent, indexNext, - linearDistance, realDistance, + realDistance, sampling, position, newpoints = [], tmpVec = new THREE.Vector3(), diff --git a/src/math/Vector2.js b/src/math/Vector2.js index 7c82e546ab87bd..ce352eea1a641a 100644 --- a/src/math/Vector2.js +++ b/src/math/Vector2.js @@ -78,7 +78,7 @@ THREE.Vector2.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -90,19 +90,19 @@ THREE.Vector2.prototype = { }, - addVectors: function ( a, b ) { + addScalar: function ( s ) { - this.x = a.x + b.x; - this.y = a.y + b.y; + this.x += s; + this.y += s; return this; }, - addScalar: function ( s ) { + addVectors: function ( a, b ) { - this.x += s; - this.y += s; + this.x = a.x + b.x; + this.y = a.y + b.y; return this; @@ -112,7 +112,7 @@ THREE.Vector2.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -124,6 +124,15 @@ THREE.Vector2.prototype = { }, + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + + return this; + + }, + subVectors: function ( a, b ) { this.x = a.x - b.x; @@ -371,9 +380,9 @@ THREE.Vector2.prototype = { lerpVectors: function ( v1, v2, alpha ) { - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - return this; + return this; }, @@ -408,14 +417,14 @@ THREE.Vector2.prototype = { fromAttribute: function ( attribute, index, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset === undefined ) offset = 0; - index = index * attribute.itemSize + offset; + index = index * attribute.itemSize + offset; - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; - return this; + return this; }, diff --git a/src/math/Vector3.js b/src/math/Vector3.js index 1f7d627b110881..6eae60a2fdd466 100644 --- a/src/math/Vector3.js +++ b/src/math/Vector3.js @@ -93,7 +93,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -130,7 +130,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -142,6 +142,16 @@ THREE.Vector3.prototype = { return this; }, + + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + + return this; + + }, subVectors: function ( a, b ) { @@ -157,7 +167,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); return this.multiplyVectors( v, w ); } @@ -198,7 +208,7 @@ THREE.Vector3.prototype = { if ( euler instanceof THREE.Euler === false ) { - console.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); + THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } @@ -599,9 +609,9 @@ THREE.Vector3.prototype = { lerpVectors: function ( v1, v2, alpha ) { - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - return this; + return this; }, @@ -609,7 +619,7 @@ THREE.Vector3.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); return this.crossVectors( v, w ); } @@ -716,19 +726,19 @@ THREE.Vector3.prototype = { setEulerFromRotationMatrix: function ( m, order ) { - console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); + THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); }, setEulerFromQuaternion: function ( q, order ) { - console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); + THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); }, getPositionFromMatrix: function ( m ) { - console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); + THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); return this.setFromMatrixPosition( m ); @@ -736,14 +746,14 @@ THREE.Vector3.prototype = { getScaleFromMatrix: function ( m ) { - console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); + THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); return this.setFromMatrixScale( m ); }, getColumnFromMatrix: function ( index, matrix ) { - console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); + THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); return this.setFromMatrixColumn( index, matrix ); @@ -773,7 +783,7 @@ THREE.Vector3.prototype = { }, setFromMatrixColumn: function ( index, matrix ) { - + var offset = index * 4; var me = matrix.elements; @@ -819,15 +829,15 @@ THREE.Vector3.prototype = { fromAttribute: function ( attribute, index, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset === undefined ) offset = 0; - index = index * attribute.itemSize + offset; + index = index * attribute.itemSize + offset; - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; - this.z = attribute.array[ index + 2 ]; + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + this.z = attribute.array[ index + 2 ]; - return this; + return this; }, diff --git a/src/math/Vector4.js b/src/math/Vector4.js index bfe0c0ba68ee1f..1a7bf50c347875 100644 --- a/src/math/Vector4.js +++ b/src/math/Vector4.js @@ -105,7 +105,7 @@ THREE.Vector4.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } @@ -145,7 +145,7 @@ THREE.Vector4.prototype = { if ( w !== undefined ) { - console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + THREE.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } @@ -159,6 +159,17 @@ THREE.Vector4.prototype = { }, + subScalar: function ( s ) { + + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; + + return this; + + }, + subVectors: function ( a, b ) { this.x = a.x - b.x; @@ -505,49 +516,49 @@ THREE.Vector4.prototype = { } )(), - floor: function () { + 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 ); + 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; + return this; - }, + }, - ceil: function () { + 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 ); + 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; + return this; - }, + }, - round: function () { + 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 ); + 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; + return this; - }, + }, - roundToZero: function () { + 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 ); + 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; + return this; - }, + }, negate: function () { @@ -617,9 +628,9 @@ THREE.Vector4.prototype = { lerpVectors: function ( v1, v2, alpha ) { - this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); - return this; + return this; }, @@ -658,16 +669,16 @@ THREE.Vector4.prototype = { fromAttribute: function ( attribute, index, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset === undefined ) offset = 0; - index = index * attribute.itemSize + offset; + index = index * attribute.itemSize + offset; - this.x = attribute.array[ index ]; - this.y = attribute.array[ index + 1 ]; - this.z = attribute.array[ index + 2 ]; - this.w = attribute.array[ index + 3 ]; + this.x = attribute.array[ index ]; + this.y = attribute.array[ index + 1 ]; + this.z = attribute.array[ index + 2 ]; + this.w = attribute.array[ index + 3 ]; - return this; + return this; }, diff --git a/src/objects/Bone.js b/src/objects/Bone.js index 9849d505ecbee9..daa4c7a5153885 100644 --- a/src/objects/Bone.js +++ b/src/objects/Bone.js @@ -4,14 +4,15 @@ * @author ikerr / http://verold.com */ -THREE.Bone = function ( belongsToSkin ) { +THREE.Bone = function ( skin ) { THREE.Object3D.call( this ); - this.skin = belongsToSkin; + this.type = 'Bone'; + + this.skin = skin; }; THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); THREE.Bone.prototype.constructor = THREE.Bone; - diff --git a/src/objects/LensFlare.js b/src/objects/LensFlare.js index 2598207e087423..0f83750cdd9a42 100644 --- a/src/objects/LensFlare.js +++ b/src/objects/LensFlare.js @@ -12,7 +12,7 @@ THREE.LensFlare = function ( texture, size, distance, blending, color ) { this.positionScreen = new THREE.Vector3(); this.customUpdateCallback = undefined; - if( texture !== undefined ) { + if ( texture !== undefined ) { this.add( texture, size, distance, blending, color ); @@ -64,7 +64,7 @@ THREE.LensFlare.prototype.updateLensFlares = function () { var vecX = - this.positionScreen.x * 2; var vecY = - this.positionScreen.y * 2; - for( f = 0; f < fl; f ++ ) { + for ( f = 0; f < fl; f ++ ) { flare = this.lensFlares[ f ]; diff --git a/src/objects/Line.js b/src/objects/Line.js index 89a324d55ff6bd..dd3e792e954fa6 100644 --- a/src/objects/Line.js +++ b/src/objects/Line.js @@ -11,7 +11,7 @@ THREE.Line = function ( geometry, material, mode ) { this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); - this.mode = ( mode !== undefined ) ? mode : THREE.LineStrip; + this.mode = mode !== undefined ? mode : THREE.LineStrip; }; @@ -72,7 +72,7 @@ THREE.Line.prototype.raycast = ( function () { } - for ( var oi = 0; oi < offsets.length; oi++){ + for ( var oi = 0; oi < offsets.length; oi ++) { var start = offsets[ oi ].start; var count = offsets[ oi ].count; diff --git a/src/objects/Mesh.js b/src/objects/Mesh.js index 3fe68e3c9e2a92..cab0a902eb8588 100644 --- a/src/objects/Mesh.js +++ b/src/objects/Mesh.js @@ -49,7 +49,7 @@ THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { } - console.log( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); + THREE.warn( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' ); return 0; @@ -90,7 +90,7 @@ THREE.Mesh.prototype.raycast = ( function () { if ( geometry.boundingBox !== null ) { - if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { + if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) { return; @@ -121,7 +121,7 @@ THREE.Mesh.prototype.raycast = ( function () { } - for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { + for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { var start = offsets[ oi ].start; var count = offsets[ oi ].count; @@ -220,7 +220,7 @@ THREE.Mesh.prototype.raycast = ( function () { var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial; var objectMaterials = isFaceMaterial === true ? this.material.materials : null; - var a, b, c, d; + var a, b, c; var precision = raycaster.precision; var vertices = geometry.vertices; diff --git a/src/objects/MorphAnimMesh.js b/src/objects/MorphAnimMesh.js index 35eb210203c421..60936c5c8ef416 100644 --- a/src/objects/MorphAnimMesh.js +++ b/src/objects/MorphAnimMesh.js @@ -70,7 +70,6 @@ THREE.MorphAnimMesh.prototype.parseAnimations = function () { if ( parts && parts.length > 1 ) { var label = parts[ 1 ]; - var num = parts[ 2 ]; if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity }; @@ -109,7 +108,7 @@ THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { } else { - console.warn( 'animation[' + label + '] undefined' ); + THREE.warn( 'THREE.MorphAnimMesh: animation[' + label + '] undefined in .playAnimation()' ); } diff --git a/src/objects/PointCloud.js b/src/objects/PointCloud.js index 9a14a6b010f3a3..e47fe5e5faed37 100644 --- a/src/objects/PointCloud.js +++ b/src/objects/PointCloud.js @@ -91,7 +91,7 @@ THREE.PointCloud.prototype.raycast = ( function () { } - for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { + for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) { var start = offsets[ oi ].start; var count = offsets[ oi ].count; @@ -157,7 +157,7 @@ THREE.PointCloud.prototype.clone = function ( object ) { THREE.ParticleSystem = function ( geometry, material ) { - console.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); + THREE.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); return new THREE.PointCloud( geometry, material ); }; diff --git a/src/objects/Skeleton.js b/src/objects/Skeleton.js index 8fbb9983990fa4..f3173c751cf253 100644 --- a/src/objects/Skeleton.js +++ b/src/objects/Skeleton.js @@ -69,7 +69,7 @@ THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) { } else { - console.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); + THREE.warn( 'THREE.Skeleton bonInverses is the wrong length.' ); this.boneInverses = []; diff --git a/src/objects/SkinnedMesh.js b/src/objects/SkinnedMesh.js index 7be365aca83f54..7c692c18bfca6e 100644 --- a/src/objects/SkinnedMesh.js +++ b/src/objects/SkinnedMesh.js @@ -25,7 +25,7 @@ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { var bone, gbone, p, q, s; - for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) { + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { gbone = this.geometry.bones[ b ]; @@ -52,7 +52,7 @@ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { } - for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) { + for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++ b ) { gbone = this.geometry.bones[ b ]; @@ -148,7 +148,7 @@ THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) { } else { - console.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode ); + THREE.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode ); } diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 94810d0c1898ed..3bef270862fc01 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -58,6 +58,7 @@ THREE.WebGLRenderer = function ( parameters ) { // physically based shading + this.gammaFactor = 2.0; // for backwards compatibility this.gammaInput = false; this.gammaOutput = false; @@ -117,29 +118,6 @@ THREE.WebGLRenderer = function ( parameters ) { _usedTextureUnits = 0, - // GL state cache - - _oldDoubleSided = - 1, - _oldFlipSided = - 1, - - _oldBlending = - 1, - - _oldBlendEquation = - 1, - _oldBlendSrc = - 1, - _oldBlendDst = - 1, - _oldBlendEquationAlpha = - 1, - _oldBlendSrcAlpha = - 1, - _oldBlendDstAlpha = - 1, - - _oldDepthTest = - 1, - _oldDepthWrite = - 1, - - _oldPolygonOffset = null, - _oldPolygonOffsetFactor = null, - _oldPolygonOffsetUnits = null, - - _oldLineWidth = null, - _viewportX = 0, _viewportY = 0, _viewportWidth = _canvas.width, @@ -147,9 +125,6 @@ THREE.WebGLRenderer = function ( parameters ) { _currentWidth = 0, _currentHeight = 0, - _newAttributes = new Uint8Array( 16 ), - _enabledAttributes = new Uint8Array( 16 ), - // frustum _frustum = new THREE.Frustum(), @@ -157,7 +132,6 @@ THREE.WebGLRenderer = function ( parameters ) { // camera matrices cache _projScreenMatrix = new THREE.Matrix4(), - _projScreenMatrixPS = new THREE.Matrix4(), _vector3 = new THREE.Vector3(), @@ -171,8 +145,8 @@ THREE.WebGLRenderer = function ( parameters ) { ambient: [ 0, 0, 0 ], directional: { length: 0, colors:[], positions: [] }, - point: { length: 0, colors: [], positions: [], distances: [] }, - spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [] }, + point: { length: 0, colors: [], positions: [], distances: [], decays: [] }, + spot: { length: 0, colors: [], positions: [], distances: [], directions: [], anglesCos: [], exponents: [], decays: [] }, hemi: { length: 0, skyColors: [], groundColors: [], positions: [] } }; @@ -221,10 +195,12 @@ THREE.WebGLRenderer = function ( parameters ) { } catch ( error ) { - console.error( error ); + THREE.error( 'THREE.WebGLRenderer: ' + error ); } + var state = new THREE.WebGLState( _gl, paramThreeToGL ); + if ( _gl.getShaderPrecisionFormat === undefined ) { _gl.getShaderPrecisionFormat = function () { @@ -243,6 +219,8 @@ THREE.WebGLRenderer = function ( parameters ) { extensions.get( 'OES_texture_float' ); extensions.get( 'OES_texture_float_linear' ); + extensions.get( 'OES_texture_half_float' ); + extensions.get( 'OES_texture_half_float_linear' ); extensions.get( 'OES_standard_derivatives' ); if ( _logarithmicDepthBuffer ) { @@ -253,6 +231,18 @@ THREE.WebGLRenderer = function ( parameters ) { // + var glClearColor = function ( r, g, b, a ) { + + if ( _premultipliedAlpha === true ) { + + r *= a; g *= a; b *= a; + + } + + _gl.clearColor( r, g, b, a ); + + }; + var setDefaultGLState = function () { _gl.clearColor( 0, 0, 0, 1 ); @@ -272,7 +262,7 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; @@ -281,27 +271,19 @@ THREE.WebGLRenderer = function ( parameters ) { _currentProgram = null; _currentCamera = null; - _oldBlending = - 1; - _oldDepthTest = - 1; - _oldDepthWrite = - 1; - _oldDoubleSided = - 1; - _oldFlipSided = - 1; _currentGeometryProgram = ''; _currentMaterialId = - 1; _lightsNeedUpdate = true; - for ( var i = 0; i < _enabledAttributes.length; i ++ ) { - - _enabledAttributes[ i ] = 0; - - } + state.reset(); }; setDefaultGLState(); this.context = _gl; + this.state = state; // GPU capabilities @@ -317,11 +299,9 @@ THREE.WebGLRenderer = function ( parameters ) { 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 getCompressedTextureFormats = ( function () { @@ -341,7 +321,7 @@ THREE.WebGLRenderer = function ( parameters ) { var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ); - for ( var i = 0; i < formats.length; i ++ ){ + for ( var i = 0; i < formats.length; i ++ ) { array.push( formats[ i ] ); @@ -365,12 +345,12 @@ THREE.WebGLRenderer = function ( parameters ) { if ( mediumpAvailable ) { _precision = 'mediump'; - console.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' ); + THREE.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' ); } else { _precision = 'lowp'; - console.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' ); + THREE.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' ); } @@ -379,7 +359,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( _precision === 'mediump' && ! mediumpAvailable ) { _precision = 'lowp'; - console.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' ); + THREE.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' ); } @@ -416,6 +396,12 @@ THREE.WebGLRenderer = function ( parameters ) { }; + this.supportsHalfFloatTextures = function () { + + return extensions.get( 'OES_texture_half_float' ); + + }; + this.supportsStandardDerivatives = function () { return extensions.get( 'OES_standard_derivatives' ); @@ -536,9 +522,10 @@ THREE.WebGLRenderer = function ( parameters ) { this.setClearColor = function ( color, alpha ) { _clearColor.set( color ); + _clearAlpha = alpha !== undefined ? alpha : 1; - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; @@ -552,7 +539,7 @@ THREE.WebGLRenderer = function ( parameters ) { _clearAlpha = alpha; - _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); + glClearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; @@ -1030,8 +1017,6 @@ THREE.WebGLRenderer = function ( parameters ) { geometry.__vertexArray = new Float32Array( nvertices * 3 ); geometry.__colorArray = new Float32Array( nvertices * 3 ); - geometry.__sortArray = []; - geometry.__webglParticleCount = nvertices; initCustomAttributes( object ); @@ -1189,19 +1174,19 @@ THREE.WebGLRenderer = function ( parameters ) { ? object.material.materials[ geometryGroup.materialIndex ] : object.material; - }; + } - function materialNeedsSmoothNormals ( material ) { + function materialNeedsFaceNormals ( material ) { - return material && material.shading !== undefined && material.shading === THREE.SmoothShading; + return material instanceof THREE.MeshPhongMaterial === false && material.shading === THREE.FlatShading; - }; + } // Buffer setting function setParticleBuffers ( geometry, hint, object ) { - var v, c, vertex, offset, index, color, + var v, c, vertex, offset, color, vertices = geometry.vertices, vl = vertices.length, @@ -1212,15 +1197,12 @@ THREE.WebGLRenderer = function ( parameters ) { 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, + ca, cal, value, customAttribute; if ( dirtyVertices ) { @@ -1379,7 +1361,7 @@ THREE.WebGLRenderer = function ( parameters ) { customAttributes = geometry.__webglCustomAttributesList, i, il, - a, ca, cal, value, + ca, cal, value, customAttribute; if ( dirtyVertices ) { @@ -1536,23 +1518,20 @@ THREE.WebGLRenderer = function ( parameters ) { } - var needsSmoothNormals = materialNeedsSmoothNormals( material ); + var needsFaceNormals = materialNeedsFaceNormals( material ); var f, fl, fi, face, - vertexNormals, faceNormal, normal, + vertexNormals, faceNormal, vertexColors, faceColor, vertexTangents, - uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, + uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3, c1, c2, c3, - sw1, sw2, sw3, sw4, - si1, si2, si3, si4, - sa1, sa2, sa3, sa4, - sb1, sb2, sb3, sb4, - m, ml, i, il, + sw1, sw2, sw3, + si1, si2, si3, + i, il, vn, uvi, uv2i, vk, vkl, vka, nka, chf, faceVertexNormals, - a, vertexIndex = 0, @@ -1567,7 +1546,6 @@ THREE.WebGLRenderer = function ( parameters ) { offset_skin = 0, offset_morphTarget = 0, offset_custom = 0, - offset_customSrc = 0, value, @@ -1607,8 +1585,6 @@ THREE.WebGLRenderer = function ( parameters ) { obj_uvs = geometry.faceVertexUvs[ 0 ], obj_uvs2 = geometry.faceVertexUvs[ 1 ], - obj_colors = geometry.colors, - obj_skinIndices = geometry.skinIndices, obj_skinWeights = geometry.skinWeights, @@ -1681,7 +1657,13 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material.morphNormals ) { - if ( needsSmoothNormals ) { + if ( needsFaceNormals ) { + + n1 = morphNormals[ vk ].faceNormals[ chf ]; + n2 = n1; + n3 = n1; + + } else { faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; @@ -1689,12 +1671,6 @@ THREE.WebGLRenderer = function ( parameters ) { n2 = faceVertexNormals.b; n3 = faceVertexNormals.c; - } else { - - n1 = morphNormals[ vk ].faceNormals[ chf ]; - n2 = n1; - n3 = n1; - } nka = morphNormalsArrays[ vk ]; @@ -1890,7 +1866,7 @@ THREE.WebGLRenderer = function ( parameters ) { vertexNormals = face.vertexNormals; faceNormal = face.normal; - if ( vertexNormals.length === 3 && needsSmoothNormals ) { + if ( vertexNormals.length === 3 && needsFaceNormals === false ) { for ( i = 0; i < 3; i ++ ) { @@ -2031,7 +2007,6 @@ THREE.WebGLRenderer = function ( parameters ) { if ( ! customAttribute.__original.needsUpdate ) continue; offset_custom = 0; - offset_customSrc = 0; if ( customAttribute.size === 1 ) { @@ -2331,7 +2306,7 @@ THREE.WebGLRenderer = function ( parameters ) { this.renderBufferImmediate = function ( object, program, material ) { - initAttributes(); + state.initAttributes(); if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); @@ -2342,7 +2317,9 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.position ); + + state.enableAttribute( program.attributes.position ); + _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } @@ -2351,7 +2328,8 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); - if ( material.shading === THREE.FlatShading ) { + if ( material instanceof THREE.MeshPhongMaterial === false && + material.shading === THREE.FlatShading ) { var nx, ny, nz, nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, @@ -2395,7 +2373,9 @@ THREE.WebGLRenderer = function ( parameters ) { } _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.normal ); + + state.enableAttribute( program.attributes.normal ); + _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } @@ -2404,7 +2384,9 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.uv ); + + state.enableAttribute( program.attributes.uv ); + _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); } @@ -2413,12 +2395,14 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); - enableAttribute( program.attributes.color ); + + state.enableAttribute( program.attributes.color ); + _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); } - disableUnusedAttributes(); + state.disableUnusedAttributes(); _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); @@ -2448,7 +2432,7 @@ THREE.WebGLRenderer = function ( parameters ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer ); - enableAttribute( programAttribute ); + state.enableAttribute( programAttribute ); _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32 @@ -2470,7 +2454,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - disableUnusedAttributes(); + state.disableUnusedAttributes(); } @@ -2495,7 +2479,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( updateBuffers ) { - initAttributes(); + state.initAttributes(); } @@ -2587,11 +2571,11 @@ THREE.WebGLRenderer = function ( parameters ) { // render non-indexed triangles - _gl.drawArrays( mode, 0, position.array.length / 3 ); + _gl.drawArrays( mode, 0, position.array.length / position.itemSize ); _this.info.render.calls ++; - _this.info.render.vertices += position.array.length / 3; - _this.info.render.faces += position.array.length / 9; + _this.info.render.vertices += position.array.length / position.itemSize; + _this.info.render.faces += position.array.length / ( 3 * position.itemSize ); } @@ -2706,7 +2690,7 @@ THREE.WebGLRenderer = function ( parameters ) { var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - setLineWidth( material.linewidth ); + state.setLineWidth( material.linewidth * pixelRatio ); var index = geometry.attributes.index; @@ -2836,7 +2820,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( updateBuffers ) { - initAttributes(); + state.initAttributes(); } @@ -2847,7 +2831,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( updateBuffers ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); - enableAttribute( attributes.position ); + + state.enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } @@ -2878,7 +2864,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); - enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); + + state.enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); + _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); } @@ -2895,7 +2883,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); - enableAttribute( attributes.color ); + + state.enableAttribute( attributes.color ); + _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues !== undefined ) { @@ -2912,7 +2902,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes.normal >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); - enableAttribute( attributes.normal ); + + state.enableAttribute( attributes.normal ); + _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } @@ -2922,7 +2914,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes.tangent >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); - enableAttribute( attributes.tangent ); + + state.enableAttribute( attributes.tangent ); + _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); } @@ -2934,7 +2928,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object.geometry.faceVertexUvs[ 0 ] ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); - enableAttribute( attributes.uv ); + + state.enableAttribute( attributes.uv ); + _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues !== undefined ) { @@ -2951,7 +2947,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object.geometry.faceVertexUvs[ 1 ] ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); - enableAttribute( attributes.uv2 ); + + state.enableAttribute( attributes.uv2 ); + _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues !== undefined ) { @@ -2967,11 +2965,15 @@ THREE.WebGLRenderer = function ( parameters ) { attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); - enableAttribute( attributes.skinIndex ); + + state.enableAttribute( attributes.skinIndex ); + _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); - enableAttribute( attributes.skinWeight ); + + state.enableAttribute( attributes.skinWeight ); + _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); } @@ -2981,14 +2983,16 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attributes.lineDistance >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); - enableAttribute( attributes.lineDistance ); + + state.enableAttribute( attributes.lineDistance ); + _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); } } - disableUnusedAttributes(); + state.disableUnusedAttributes(); // render mesh @@ -3000,7 +3004,8 @@ THREE.WebGLRenderer = function ( parameters ) { if ( material.wireframe ) { - setLineWidth( material.wireframeLinewidth ); + state.setLineWidth( material.wireframeLinewidth * pixelRatio ); + if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, type, 0 ); @@ -3023,7 +3028,7 @@ THREE.WebGLRenderer = function ( parameters ) { var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; - setLineWidth( material.linewidth ); + state.setLineWidth( material.linewidth * pixelRatio ); _gl.drawArrays( mode, 0, geometryGroup.__webglLineCount ); @@ -3042,44 +3047,6 @@ THREE.WebGLRenderer = function ( parameters ) { }; - function initAttributes() { - - for ( var i = 0, l = _newAttributes.length; i < l; i ++ ) { - - _newAttributes[ i ] = 0; - - } - - } - - function enableAttribute( attribute ) { - - _newAttributes[ attribute ] = 1; - - if ( _enabledAttributes[ attribute ] === 0 ) { - - _gl.enableVertexAttribArray( attribute ); - _enabledAttributes[ attribute ] = 1; - - } - - } - - function disableUnusedAttributes() { - - for ( var i = 0, l = _enabledAttributes.length; i < l; i ++ ) { - - if ( _enabledAttributes[ i ] !== _newAttributes[ i ] ) { - - _gl.disableVertexAttribArray( i ); - _enabledAttributes[ i ] = 0; - - } - - } - - } - function setupMorphTargets ( material, geometryGroup, object ) { // set base @@ -3089,13 +3056,17 @@ THREE.WebGLRenderer = function ( parameters ) { if ( object.morphTargetBase !== - 1 && attributes.position >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); - enableAttribute( attributes.position ); + + state.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 ); + + state.enableAttribute( attributes.position ); + _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } @@ -3117,7 +3088,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attribute >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); - enableAttribute( attribute ); + + state.enableAttribute( attribute ); + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); } @@ -3127,7 +3100,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attribute >= 0 && material.morphNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); - enableAttribute( attribute ); + + state.enableAttribute( attribute ); + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); } @@ -3144,6 +3119,14 @@ THREE.WebGLRenderer = function ( parameters ) { var activeInfluenceIndices = []; var influences = object.morphTargetInfluences; + var morphTargets = object.geometry.morphTargets; + + if ( influences.length > morphTargets.length ) { + + console.warn( 'THREE.WebGLRenderer: Influences array is bigger than morphTargets array.' ); + influences.length = morphTargets.length; + + } for ( var i = 0, il = influences.length; i < il; i ++ ) { @@ -3181,7 +3164,9 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attribute >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); - enableAttribute( attribute ); + + state.enableAttribute( attribute ); + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); } @@ -3191,9 +3176,10 @@ THREE.WebGLRenderer = function ( parameters ) { if ( attribute >= 0 && material.morphNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); - enableAttribute( attribute ); - _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); + state.enableAttribute( attribute ); + + _gl.vertexAttribPointer( attribute, 3, _gl.FLOAT, false, 0, 0 ); } @@ -3233,7 +3219,11 @@ THREE.WebGLRenderer = function ( parameters ) { function painterSortStable ( a, b ) { - if ( a.material.id !== b.material.id ) { + if ( a.object.renderOrder !== b.object.renderOrder ) { + + return a.object.renderOrder - b.object.renderOrder; + + } else if ( a.material.id !== b.material.id ) { return a.material.id - b.material.id; @@ -3251,7 +3241,11 @@ THREE.WebGLRenderer = function ( parameters ) { function reversePainterSortStable ( a, b ) { - if ( a.z !== b.z ) { + if ( a.object.renderOrder !== b.object.renderOrder ) { + + return a.object.renderOrder - b.object.renderOrder; + + } if ( a.z !== b.z ) { return b.z - a.z; @@ -3275,7 +3269,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.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); return; } @@ -3368,32 +3362,27 @@ THREE.WebGLRenderer = function ( parameters ) { if ( scene.overrideMaterial ) { - var material = scene.overrideMaterial; + var overrideMaterial = scene.overrideMaterial; - this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - this.setDepthTest( material.depthTest ); - this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + setMaterial( overrideMaterial ); - renderObjects( opaqueObjects, camera, lights, fog, true, material ); - renderObjects( transparentObjects, camera, lights, fog, true, material ); - renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, false, material ); + renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial ); + renderObjects( transparentObjects, camera, lights, fog, overrideMaterial ); + renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, overrideMaterial ); } else { - var material = null; - // opaque pass (front-to-back order) - this.setBlending( THREE.NoBlending ); + state.setBlending( THREE.NoBlending ); - renderObjects( opaqueObjects, camera, lights, fog, false, material ); - renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, false, material ); + renderObjects( opaqueObjects, camera, lights, fog, null ); + renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, null ); // transparent pass (back-to-front order) - renderObjects( transparentObjects, camera, lights, fog, true, material ); - renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, true, material ); + renderObjects( transparentObjects, camera, lights, fog, null ); + renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, null ); } @@ -3412,8 +3401,9 @@ THREE.WebGLRenderer = function ( parameters ) { // Ensure depth buffer writing is enabled so it can be cleared on next render - this.setDepthTest( true ); - this.setDepthWrite( true ); + state.setDepthTest( true ); + state.setDepthWrite( true ); + state.setColorWrite( true ); // _gl.finish(); @@ -3451,7 +3441,7 @@ THREE.WebGLRenderer = function ( parameters ) { for ( var i = 0, l = webglObjects.length; i < l; i ++ ) { - var webglObject = webglObjects[i]; + var webglObject = webglObjects[ i ]; unrollBufferMaterial( webglObject ); @@ -3482,7 +3472,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - function renderObjects( renderList, camera, lights, fog, useBlending, overrideMaterial ) { + function renderObjects( renderList, camera, lights, fog, overrideMaterial ) { var material; @@ -3505,11 +3495,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( ! material ) continue; - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + setMaterial( material ); } @@ -3529,7 +3515,7 @@ THREE.WebGLRenderer = function ( parameters ) { } - function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { + function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) { var material; @@ -3550,11 +3536,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( ! material ) continue; - if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); - - _this.setDepthTest( material.depthTest ); - _this.setDepthWrite( material.depthWrite ); - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + setMaterial( material ); } @@ -3926,20 +3908,36 @@ THREE.WebGLRenderer = function ( parameters ) { var key = attributesKeys[ i ]; var attribute = attributes[ key ]; + var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; if ( attribute.buffer === undefined ) { attribute.buffer = _gl.createBuffer(); - attribute.needsUpdate = true; - - } + _gl.bindBuffer( bufferType, attribute.buffer ); + _gl.bufferData( bufferType, attribute.array, ( attribute instanceof THREE.DynamicBufferAttribute ) ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW ); - if ( attribute.needsUpdate === true ) { + attribute.needsUpdate = false; - var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER; + } else if ( attribute.needsUpdate === true ) { _gl.bindBuffer( bufferType, attribute.buffer ); - _gl.bufferData( bufferType, attribute.array, _gl.STATIC_DRAW ); + + if ( attribute.updateRange === undefined || attribute.updateRange.count === -1 ) { // Not using update ranges + + _gl.bufferSubData( bufferType, 0, attribute.array ); + + } else if ( attribute.updateRange.count === 0 ) { + + console.error( 'THREE.WebGLRenderer.updateObject: using updateRange for THREE.DynamicBufferAttribute and marked as needsUpdate but count is 0, ensure you are using set methods or updating manually.' ); + + } else { + + _gl.bufferSubData( bufferType, attribute.updateRange.offset * attribute.array.BYTES_PER_ELEMENT, + attribute.array.subarray( attribute.updateRange.offset, attribute.updateRange.offset + attribute.updateRange.count ) ); + + attribute.updateRange.count = 0; // reset range + + } attribute.needsUpdate = false; @@ -3964,12 +3962,6 @@ THREE.WebGLRenderer = function ( parameters ) { var geometryGroup = geometryGroupsList[ i ]; var material = getBufferMaterial( object, geometryGroup ); - if ( geometry.groupsNeedUpdate === true ) { - - initMeshBuffers( geometryGroup, object ); - - } - var customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || @@ -4159,6 +4151,8 @@ THREE.WebGLRenderer = function ( parameters ) { useFog: material.fog, fogExp: fog instanceof THREE.FogExp2, + flatShading: material.shading === THREE.FlatShading, + sizeAttenuation: material.sizeAttenuation, logarithmicDepthBuffer: _logarithmicDepthBuffer, @@ -4311,6 +4305,25 @@ THREE.WebGLRenderer = function ( parameters ) { } + function setMaterial( material ) { + + if ( material.transparent === true ) { + + state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha ); + + } else { + + state.setBlending( THREE.NoBlending ); + + } + + state.setDepthTest( material.depthTest ); + state.setDepthWrite( material.depthWrite ); + state.setColorWrite( material.colorWrite ); + state.setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + + } + function setProgram( camera, lights, fog, material, object ) { _usedTextureUnits = 0; @@ -4563,15 +4576,7 @@ 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; @@ -4635,17 +4640,7 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.envMap.value = material.envMap; uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : - 1; - if ( _this.gammaInput ) { - - //uniforms.reflectivity.value = material.reflectivity * material.reflectivity; - uniforms.reflectivity.value = material.reflectivity; - - } else { - - uniforms.reflectivity.value = material.reflectivity; - - } - + uniforms.reflectivity.value = material.reflectivity; uniforms.refractionRatio.value = material.refractionRatio; } @@ -4674,6 +4669,15 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.map.value = material.map; + if ( material.map !== null ) { + + var offset = material.map.offset; + var repeat = material.map.repeat; + + uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); + + } + } function refreshUniformsFog ( uniforms, fog ) { @@ -4697,17 +4701,8 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.shininess.value = material.shininess; - if ( _this.gammaInput ) { - - uniforms.emissive.value.copyGammaToLinear( material.emissive ); - uniforms.specular.value.copyGammaToLinear( material.specular ); - - } else { - - uniforms.emissive.value = material.emissive; - uniforms.specular.value = material.specular; - - } + uniforms.emissive.value = material.emissive; + uniforms.specular.value = material.specular; if ( material.wrapAround ) { @@ -4719,15 +4714,7 @@ THREE.WebGLRenderer = function ( parameters ) { function refreshUniformsLambert ( uniforms, material ) { - if ( _this.gammaInput ) { - - uniforms.emissive.value.copyGammaToLinear( material.emissive ); - - } else { - - uniforms.emissive.value = material.emissive; - - } + uniforms.emissive.value = material.emissive; if ( material.wrapAround ) { @@ -4747,6 +4734,7 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.pointLightColor.value = lights.point.colors; uniforms.pointLightPosition.value = lights.point.positions; uniforms.pointLightDistance.value = lights.point.distances; + uniforms.pointLightDecay.value = lights.point.decays; uniforms.spotLightColor.value = lights.spot.colors; uniforms.spotLightPosition.value = lights.spot.positions; @@ -4754,6 +4742,7 @@ THREE.WebGLRenderer = function ( parameters ) { uniforms.spotLightDirection.value = lights.spot.directions; uniforms.spotLightAngleCos.value = lights.spot.anglesCos; uniforms.spotLightExponent.value = lights.spot.exponents; + uniforms.spotLightDecay.value = lights.spot.decays; uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; @@ -4763,27 +4752,29 @@ THREE.WebGLRenderer = function ( parameters ) { // If uniforms are marked as clean, they don't need to be loaded to the GPU. - function markUniformsLightsNeedsUpdate ( uniforms, boolean ) { + function markUniformsLightsNeedsUpdate ( uniforms, value ) { - uniforms.ambientLightColor.needsUpdate = boolean; + uniforms.ambientLightColor.needsUpdate = value; - uniforms.directionalLightColor.needsUpdate = boolean; - uniforms.directionalLightDirection.needsUpdate = boolean; + uniforms.directionalLightColor.needsUpdate = value; + uniforms.directionalLightDirection.needsUpdate = value; - uniforms.pointLightColor.needsUpdate = boolean; - uniforms.pointLightPosition.needsUpdate = boolean; - uniforms.pointLightDistance.needsUpdate = boolean; + uniforms.pointLightColor.needsUpdate = value; + uniforms.pointLightPosition.needsUpdate = value; + uniforms.pointLightDistance.needsUpdate = value; + uniforms.pointLightDecay.needsUpdate = value; - uniforms.spotLightColor.needsUpdate = boolean; - uniforms.spotLightPosition.needsUpdate = boolean; - uniforms.spotLightDistance.needsUpdate = boolean; - uniforms.spotLightDirection.needsUpdate = boolean; - uniforms.spotLightAngleCos.needsUpdate = boolean; - uniforms.spotLightExponent.needsUpdate = boolean; + uniforms.spotLightColor.needsUpdate = value; + uniforms.spotLightPosition.needsUpdate = value; + uniforms.spotLightDistance.needsUpdate = value; + uniforms.spotLightDirection.needsUpdate = value; + uniforms.spotLightAngleCos.needsUpdate = value; + uniforms.spotLightExponent.needsUpdate = value; + uniforms.spotLightDecay.needsUpdate = value; - uniforms.hemisphereLightSkyColor.needsUpdate = boolean; - uniforms.hemisphereLightGroundColor.needsUpdate = boolean; - uniforms.hemisphereLightDirection.needsUpdate = boolean; + uniforms.hemisphereLightSkyColor.needsUpdate = value; + uniforms.hemisphereLightGroundColor.needsUpdate = value; + uniforms.hemisphereLightDirection.needsUpdate = value; } @@ -4839,7 +4830,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( textureUnit >= _maxTextures ) { - console.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures ); + THREE.warn( 'WebGLRenderer: trying to use ' + textureUnit + ' texture units while this GPU supports only ' + _maxTextures ); } @@ -5177,7 +5168,7 @@ THREE.WebGLRenderer = function ( parameters ) { default: - console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); + THREE.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); } @@ -5192,16 +5183,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 ) { array[ offset ] = color.r * intensity; @@ -5212,11 +5193,10 @@ THREE.WebGLRenderer = function ( parameters ) { function setupLights ( lights ) { - var l, ll, light, n, + var l, ll, light, r = 0, g = 0, b = 0, color, skyColor, groundColor, - intensity, intensitySq, - position, + intensity, distance, zlights = _lights, @@ -5227,6 +5207,7 @@ THREE.WebGLRenderer = function ( parameters ) { pointColors = zlights.point.colors, pointPositions = zlights.point.positions, pointDistances = zlights.point.distances, + pointDecays = zlights.point.decays, spotColors = zlights.spot.colors, spotPositions = zlights.spot.positions, @@ -5234,6 +5215,7 @@ THREE.WebGLRenderer = function ( parameters ) { spotDirections = zlights.spot.directions, spotAnglesCos = zlights.spot.anglesCos, spotExponents = zlights.spot.exponents, + spotDecays = zlights.spot.decays, hemiSkyColors = zlights.hemi.skyColors, hemiGroundColors = zlights.hemi.groundColors, @@ -5268,19 +5250,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 ) { @@ -5299,15 +5271,7 @@ 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; @@ -5319,15 +5283,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 ); @@ -5335,7 +5291,9 @@ THREE.WebGLRenderer = function ( parameters ) { pointPositions[ pointOffset + 1 ] = _vector3.y; pointPositions[ pointOffset + 2 ] = _vector3.z; + // distance is 0 if decay is 0, because there is no attenuation at all. pointDistances[ pointLength ] = distance; + pointDecays[ pointLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; pointLength += 1; @@ -5347,15 +5305,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 ); _direction.setFromMatrixPosition( light.matrixWorld ); @@ -5375,6 +5325,7 @@ THREE.WebGLRenderer = function ( parameters ) { spotAnglesCos[ spotLength ] = Math.cos( light.angle ); spotExponents[ spotLength ] = light.exponent; + spotDecays[ spotLength ] = ( light.distance === 0 ) ? 0.0 : light.decay; spotLength += 1; @@ -5396,19 +5347,8 @@ THREE.WebGLRenderer = function ( parameters ) { skyColor = light.color; groundColor = light.groundColor; - if ( _this.gammaInput ) { - - intensitySq = intensity * intensity; - - setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq ); - setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq ); - - } else { - - setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); - setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); - - } + setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); + setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); hemiLength += 1; @@ -5478,197 +5418,8 @@ THREE.WebGLRenderer = function ( parameters ) { 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 ) { - - width *= pixelRatio; - - 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, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { - - 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 ) { - - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; - - if ( blendEquation !== _oldBlendEquation || blendEquationAlpha !== _oldBlendEquationAlpha ) { - - _gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); - - _oldBlendEquation = blendEquation; - _oldBlendEquationAlpha = blendEquationAlpha; - - } - - if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst || blendSrcAlpha !== _oldBlendSrcAlpha || blendDstAlpha !== _oldBlendDstAlpha ) { - - _gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); - - _oldBlendSrc = blendSrc; - _oldBlendDst = blendDst; - _oldBlendSrcAlpha = blendSrcAlpha; - _oldBlendDstAlpha = blendDstAlpha; - - } - - } else { - - _oldBlendEquation = null; - _oldBlendSrc = null; - _oldBlendDst = null; - _oldBlendEquationAlpha = null; - _oldBlendSrcAlpha = null; - _oldBlendDstAlpha = null; - - } + state.setDoubleSided( material.side === THREE.DoubleSide ); + state.setFlipSided( material.side === THREE.BackSide ); }; @@ -5693,7 +5444,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( texture.wrapS !== THREE.ClampToEdgeWrapping || texture.wrapT !== THREE.ClampToEdgeWrapping ) { - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT is set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' ); + THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping. ( ' + texture.sourceFile + ' )' ); } @@ -5702,7 +5453,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( texture.minFilter !== THREE.NearestFilter && texture.minFilter !== THREE.LinearFilter ) { - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter is set to THREE.LinearFilter or THREE.NearestFilter. ( ' + texture.sourceFile + ' )' ); + THREE.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter. ( ' + texture.sourceFile + ' )' ); } @@ -5710,12 +5461,12 @@ THREE.WebGLRenderer = function ( parameters ) { extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - if ( extension && texture.type !== THREE.FloatType ) { + if ( extension && texture.type !== THREE.FloatType && texture.type !== THREE.HalfFloatType ) { - if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { + if ( texture.anisotropy > 1 || texture.__currentAnisotropy ) { _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) ); - texture.__oldAnisotropy = texture.anisotropy; + texture.__currentAnisotropy = texture.anisotropy; } @@ -5791,7 +5542,7 @@ THREE.WebGLRenderer = function ( parameters ) { } else { - console.warn( "Attempt to load unsupported compressed texture format" ); + THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()" ); } @@ -5868,7 +5619,7 @@ THREE.WebGLRenderer = function ( parameters ) { var context = canvas.getContext( '2d' ); context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); - console.log( 'THREE.WebGLRenderer:', image, 'is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height + '.' ); + THREE.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height, image ); return canvas; @@ -5955,7 +5706,7 @@ THREE.WebGLRenderer = function ( parameters ) { } else { - console.warn( "Attempt to load unsupported compressed texture format" ); + THREE.warn( "THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setCubeTexture()" ); } @@ -6187,49 +5938,49 @@ THREE.WebGLRenderer = function ( parameters ) { this.readRenderTargetPixels = function( renderTarget, x, y, width, height, buffer ) { - if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) { + if ( ! ( renderTarget instanceof THREE.WebGLRenderTarget ) ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - } + } - if ( renderTarget.__webglFramebuffer ) { + if ( renderTarget.__webglFramebuffer ) { - if ( renderTarget.format !== THREE.RGBAFormat ) { + if ( renderTarget.format !== THREE.RGBAFormat ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' ); - return; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA format. readPixels can read only RGBA format.' ); + return; - } + } - var restore = false; + var restore = false; - if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) { + if ( renderTarget.__webglFramebuffer !== _currentFramebuffer ) { - _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, renderTarget.__webglFramebuffer ); - restore = true; + restore = true; - } + } - if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { + if ( _gl.checkFramebufferStatus( _gl.FRAMEBUFFER ) === _gl.FRAMEBUFFER_COMPLETE ) { - _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer ); + _gl.readPixels( x, y, width, height, _gl.RGBA, _gl.UNSIGNED_BYTE, buffer ); - } else { + } else { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - } + } - if ( restore ) { + if ( restore ) { - _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); + _gl.bindFramebuffer( _gl.FRAMEBUFFER, _currentFramebuffer ); - } + } - } + } }; @@ -6295,6 +6046,14 @@ THREE.WebGLRenderer = function ( parameters ) { if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; if ( p === THREE.FloatType ) return _gl.FLOAT; + extension = extensions.get( 'OES_texture_half_float' ); + + if ( extension !== null ) { + + if ( p === THREE.HalfFloatType ) return extension.HALF_FLOAT_OES; + + } + if ( p === THREE.AlphaFormat ) return _gl.ALPHA; if ( p === THREE.RGBFormat ) return _gl.RGB; if ( p === THREE.RGBAFormat ) return _gl.RGBA; @@ -6382,7 +6141,7 @@ THREE.WebGLRenderer = function ( parameters ) { if ( maxBones < object.skeleton.bones.length ) { - console.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); + THREE.warn( 'WebGLRenderer: too many bones - ' + object.skeleton.bones.length + ', this GPU supports just ' + maxBones + ' (try OpenGL instead of ANGLE)' ); } @@ -6441,25 +6200,25 @@ THREE.WebGLRenderer = function ( parameters ) { this.initMaterial = function () { - console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); + THREE.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); }; this.addPrePlugin = function () { - console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); + THREE.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); }; this.addPostPlugin = function () { - console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); + THREE.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); }; this.updateShadowMap = function () { - console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); + THREE.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); }; diff --git a/src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl b/src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl index 976c607cad4960..1aa712eb3aaa9c 100644 --- a/src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl @@ -1,5 +1,5 @@ #ifdef USE_ALPHAMAP - gl_FragColor.a *= texture2D( alphaMap, vUv ).g; + diffuseColor.a *= texture2D( alphaMap, vUv ).g; #endif diff --git a/src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl b/src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl index e7d97a3b71bd57..448b2bf55661f7 100644 --- a/src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl @@ -1,5 +1,5 @@ #ifdef ALPHATEST - if ( gl_FragColor.a < ALPHATEST ) discard; + if ( diffuseColor.a < ALPHATEST ) discard; #endif diff --git a/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl index 51a26a77428723..c901f0b0135cc5 100644 --- a/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/bumpmap_pars_fragment.glsl @@ -3,10 +3,10 @@ uniform sampler2D bumpMap; uniform float bumpScale; - // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen - // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html + // 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) + // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) vec2 dHdxy_fwd() { @@ -37,4 +37,4 @@ } -#endif \ No newline at end of file +#endif diff --git a/src/renderers/shaders/ShaderChunk/color_fragment.glsl b/src/renderers/shaders/ShaderChunk/color_fragment.glsl index 7a657096e95629..693fdf061c226f 100644 --- a/src/renderers/shaders/ShaderChunk/color_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/color_fragment.glsl @@ -1,5 +1,5 @@ #ifdef USE_COLOR - gl_FragColor = gl_FragColor * vec4( vColor, 1.0 ); + diffuseColor.rgb *= vColor; #endif \ No newline at end of file diff --git a/src/renderers/shaders/ShaderChunk/color_vertex.glsl b/src/renderers/shaders/ShaderChunk/color_vertex.glsl index 34439eed4e290f..70260dfcfa0dd1 100644 --- a/src/renderers/shaders/ShaderChunk/color_vertex.glsl +++ b/src/renderers/shaders/ShaderChunk/color_vertex.glsl @@ -1,13 +1,5 @@ #ifdef USE_COLOR - #ifdef GAMMA_INPUT - - vColor = square( color ); - - #else - - vColor = color; - - #endif + vColor.xyz = inputToLinear( color.xyz ); #endif \ No newline at end of file diff --git a/src/renderers/shaders/ShaderChunk/common.glsl b/src/renderers/shaders/ShaderChunk/common.glsl index b14850181ee351..1c5a22610cb740 100644 --- a/src/renderers/shaders/ShaderChunk/common.glsl +++ b/src/renderers/shaders/ShaderChunk/common.glsl @@ -36,4 +36,25 @@ float sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) { } vec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) { return pointOnLine + lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ); -} \ No newline at end of file +} +float calcLightAttenuation( float lightDistance, float cutoffDistance, float decayExponent ) { + if ( decayExponent > 0.0 ) { + return pow( saturate( 1.0 - lightDistance / cutoffDistance ), decayExponent ); + } + return 1.0; +} + +vec3 inputToLinear( in vec3 a ) { +#ifdef GAMMA_INPUT + return pow( a, vec3( float( GAMMA_FACTOR ) ) ); +#else + return a; +#endif +} +vec3 linearToOutput( in vec3 a ) { +#ifdef GAMMA_OUTPUT + return pow( a, vec3( 1.0 / float( GAMMA_FACTOR ) ) ); +#else + return a; +#endif +} diff --git a/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl b/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl index 3b9e2e1cd9cbcf..28b50198adff4a 100644 --- a/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl @@ -37,29 +37,25 @@ sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 ); sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5; vec4 envColor = texture2D( envMap, sampleUV ); - + #elif defined( ENVMAP_TYPE_SPHERE ) vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0)); vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 ); #endif - #ifdef GAMMA_INPUT - - envColor.xyz *= envColor.xyz; - - #endif + envColor.xyz = inputToLinear( envColor.xyz ); #ifdef ENVMAP_BLENDING_MULTIPLY - gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * envColor.xyz, specularStrength * reflectivity ); + outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity ); #elif defined( ENVMAP_BLENDING_MIX ) - gl_FragColor.xyz = mix( gl_FragColor.xyz, envColor.xyz, specularStrength * reflectivity ); + outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity ); #elif defined( ENVMAP_BLENDING_ADD ) - gl_FragColor.xyz += envColor.xyz * specularStrength * reflectivity; + outgoingLight += envColor.xyz * specularStrength * reflectivity; #endif diff --git a/src/renderers/shaders/ShaderChunk/fog_fragment.glsl b/src/renderers/shaders/ShaderChunk/fog_fragment.glsl index d28e65071b21ef..1047f767caa7f8 100644 --- a/src/renderers/shaders/ShaderChunk/fog_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/fog_fragment.glsl @@ -21,6 +21,6 @@ #endif - gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor ); + outgoingLight = mix( outgoingLight, fogColor, fogFactor ); #endif \ No newline at end of file diff --git a/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl b/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl index 5f4afaa00e6046..586e98270fe641 100644 --- a/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl @@ -1,5 +1,5 @@ #ifdef USE_LIGHTMAP - gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 ); + outgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz; #endif \ No newline at end of file diff --git a/src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl b/src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl index f067fa527cfea4..ee521477b21209 100644 --- a/src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl +++ b/src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl @@ -1,6 +1,3 @@ -uniform vec3 diffuse; -uniform vec3 emissive; - uniform vec3 ambientLightColor; #if MAX_DIR_LIGHTS > 0 @@ -23,6 +20,7 @@ uniform vec3 ambientLightColor; uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ]; uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ]; uniform float pointLightDistance[ MAX_POINT_LIGHTS ]; + uniform float pointLightDecay[ MAX_POINT_LIGHTS ]; #endif @@ -34,6 +32,7 @@ uniform vec3 ambientLightColor; uniform float spotLightDistance[ MAX_SPOT_LIGHTS ]; uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ]; uniform float spotLightExponent[ MAX_SPOT_LIGHTS ]; + uniform float spotLightDecay[ MAX_SPOT_LIGHTS ]; #endif diff --git a/src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl b/src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl index 64d24832ea2376..864b07ca5bff46 100644 --- a/src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl +++ b/src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl @@ -61,9 +61,7 @@ for( int i = 0; i < MAX_DIR_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 ); + float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] ); lVector = normalize( lVector ); float dotProduct = dot( transformedNormal, lVector ); @@ -95,11 +93,11 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) { #endif - vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance; + vLightFront += pointLightColor[ i ] * pointLightWeighting * attenuation; #ifdef DOUBLE_SIDED - vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance; + vLightBack += pointLightColor[ i ] * pointLightWeightingBack * attenuation; #endif @@ -120,9 +118,7 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) { spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 ); - float lDistance = 1.0; - if ( spotLightDistance[ i ] > 0.0 ) - lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 ); + float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] ); lVector = normalize( lVector ); @@ -154,11 +150,11 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) { #endif - vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect; + vLightFront += spotLightColor[ i ] * spotLightWeighting * attenuation * spotEffect; #ifdef DOUBLE_SIDED - vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect; + vLightBack += spotLightColor[ i ] * spotLightWeightingBack * attenuation * spotEffect; #endif @@ -191,10 +187,10 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) { #endif -vLightFront = vLightFront * diffuse + diffuse * ambientLightColor + emissive; +vLightFront += ambientLightColor; #ifdef DOUBLE_SIDED - vLightBack = vLightBack * diffuse + diffuse * ambientLightColor + emissive; - -#endif \ No newline at end of file + vLightBack += ambientLightColor; + +#endif diff --git a/src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl b/src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl index 5757ae38a889f7..ff829891b75ac6 100644 --- a/src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl @@ -1,12 +1,23 @@ -vec3 normal = normalize( vNormal ); -vec3 viewPosition = normalize( vViewPosition ); +#ifndef FLAT_SHADED + + vec3 normal = normalize( vNormal ); + + #ifdef DOUBLE_SIDED + + normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) ); + + #endif -#ifdef DOUBLE_SIDED +#else - normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) ); + vec3 fdx = dFdx( vViewPosition ); + vec3 fdy = dFdy( vViewPosition ); + vec3 normal = normalize( cross( fdx, fdy ) ); #endif +vec3 viewPosition = normalize( vViewPosition ); + #ifdef USE_NORMALMAP normal = perturbNormal2Arb( -vViewPosition, normal ); @@ -17,23 +28,21 @@ vec3 viewPosition = normalize( vViewPosition ); #endif -#if MAX_POINT_LIGHTS > 0 +vec3 totalDiffuseLight = vec3( 0.0 ); +vec3 totalSpecularLight = vec3( 0.0 ); - vec3 pointDiffuse = vec3( 0.0 ); - vec3 pointSpecular = vec3( 0.0 ); +#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 lDistance = 1.0; - if ( pointLightDistance[ i ] > 0.0 ) - lDistance = saturate( 1.0 - ( length( lVector ) / pointLightDistance[ i ] ) ); + float attenuation = calcLightAttenuation( length( lVector ), pointLightDistance[ i ], pointLightDecay[ i ] ); lVector = normalize( lVector ); - // diffuse + // diffuse float dotProduct = dot( normal, lVector ); @@ -50,7 +59,7 @@ vec3 viewPosition = normalize( vViewPosition ); #endif - pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance; + totalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation; // specular @@ -61,7 +70,7 @@ vec3 viewPosition = normalize( vViewPosition ); float specularNormalization = ( shininess + 2.0 ) / 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; + totalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization; } @@ -69,17 +78,12 @@ vec3 viewPosition = normalize( vViewPosition ); #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 = saturate( 1.0 - ( length( lVector ) / spotLightDistance[ i ] ) ); + float attenuation = calcLightAttenuation( length( lVector ), spotLightDistance[ i ], spotLightDecay[ i ] ); lVector = normalize( lVector ); @@ -89,7 +93,7 @@ vec3 viewPosition = normalize( vViewPosition ); spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 ); - // diffuse + // diffuse float dotProduct = dot( normal, lVector ); @@ -106,9 +110,9 @@ vec3 viewPosition = normalize( vViewPosition ); #endif - spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect; + totalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect; - // specular + // specular vec3 spotHalfVector = normalize( lVector + viewPosition ); float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 ); @@ -117,7 +121,7 @@ vec3 viewPosition = normalize( vViewPosition ); float specularNormalization = ( shininess + 2.0 ) / 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; + totalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect; } @@ -127,14 +131,11 @@ vec3 viewPosition = normalize( vViewPosition ); #if MAX_DIR_LIGHTS > 0 - vec3 dirDiffuse = vec3( 0.0 ); - vec3 dirSpecular = vec3( 0.0 ); - for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) { vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix ); - // diffuse + // diffuse float dotProduct = dot( normal, dirVector ); @@ -151,7 +152,7 @@ vec3 viewPosition = normalize( vViewPosition ); #endif - dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight; + totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight; // specular @@ -183,7 +184,7 @@ vec3 viewPosition = normalize( vViewPosition ); // 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; + totalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization; } @@ -192,9 +193,6 @@ vec3 viewPosition = normalize( vViewPosition ); #if MAX_HEMI_LIGHTS > 0 - vec3 hemiDiffuse = vec3( 0.0 ); - vec3 hemiSpecular = vec3( 0.0 ); - for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) { vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix ); @@ -206,7 +204,7 @@ vec3 viewPosition = normalize( vViewPosition ); vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ); - hemiDiffuse += diffuse * hemiColor; + totalDiffuseLight += hemiColor; // specular (sky light) @@ -228,49 +226,18 @@ vec3 viewPosition = normalize( vViewPosition ); 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 ) ); + totalSpecularLight += 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 * diffuse + totalSpecular ); + outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive; #else - gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * diffuse ) + totalSpecular; + outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive; -#endif \ No newline at end of file +#endif diff --git a/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl index 54228c49bd5b8d..28bb67544b1ffe 100644 --- a/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/lights_phong_pars_fragment.glsl @@ -21,6 +21,7 @@ uniform vec3 ambientLightColor; uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ]; uniform float pointLightDistance[ MAX_POINT_LIGHTS ]; + uniform float pointLightDecay[ MAX_POINT_LIGHTS ]; #endif @@ -31,8 +32,8 @@ uniform vec3 ambientLightColor; 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 spotLightDecay[ MAX_SPOT_LIGHTS ]; #endif @@ -49,4 +50,9 @@ uniform vec3 ambientLightColor; #endif varying vec3 vViewPosition; -varying vec3 vNormal; \ No newline at end of file + +#ifndef FLAT_SHADED + + varying vec3 vNormal; + +#endif diff --git a/src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl b/src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl index 1af6c29d2f00bb..365c6dd0a2aacd 100644 --- a/src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl @@ -1,5 +1,2 @@ -#ifdef GAMMA_OUTPUT - gl_FragColor.xyz = sqrt( gl_FragColor.xyz ); - -#endif \ No newline at end of file + outgoingLight = linearToOutput( outgoingLight ); diff --git a/src/renderers/shaders/ShaderChunk/map_fragment.glsl b/src/renderers/shaders/ShaderChunk/map_fragment.glsl index 7773eebbc37a8f..467a1c450e8d44 100644 --- a/src/renderers/shaders/ShaderChunk/map_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/map_fragment.glsl @@ -2,12 +2,8 @@ vec4 texelColor = texture2D( map, vUv ); - #ifdef GAMMA_INPUT + texelColor.xyz = inputToLinear( texelColor.xyz ); - texelColor.xyz *= texelColor.xyz; - - #endif - - gl_FragColor = gl_FragColor * texelColor; + diffuseColor *= texelColor; #endif \ No newline at end of file diff --git a/src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl b/src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl index 3faf7b91fd6c75..1bc3cbe59852ef 100644 --- a/src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl @@ -1,5 +1,5 @@ #ifdef USE_MAP - gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) ); + diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy ); -#endif \ No newline at end of file +#endif diff --git a/src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl index 754690cc63ce82..cc3c236659a05a 100644 --- a/src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/map_particle_pars_fragment.glsl @@ -1,5 +1,6 @@ #ifdef USE_MAP + uniform vec4 offsetRepeat; uniform sampler2D map; -#endif \ No newline at end of file +#endif diff --git a/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl b/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl index 1cb3b42fcd1c86..54b93eb59fb3d4 100644 --- a/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/normalmap_pars_fragment.glsl @@ -3,8 +3,8 @@ uniform sampler2D normalMap; uniform vec2 normalScale; - // Per-Pixel Tangent Space Normal Mapping - // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html + // 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 ) { diff --git a/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl b/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl index 87e592d37f13d4..c5e7f35bacf8a4 100644 --- a/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl +++ b/src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl @@ -197,11 +197,11 @@ #ifdef SHADOWMAP_CASCADE - if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ]; + if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ]; #else - if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ]; + if ( inFrustum ) outgoingLight *= frustumColors[ i ]; #endif @@ -209,12 +209,9 @@ } - #ifdef GAMMA_OUTPUT + // NOTE: I am unsure if this is correct in linear space. -bhouston, Dec 29, 2014 + shadowColor = inputToLinear( shadowColor ); - shadowColor *= shadowColor; - - #endif - - gl_FragColor.xyz = gl_FragColor.xyz * shadowColor; + outgoingLight = outgoingLight * shadowColor; #endif diff --git a/src/renderers/shaders/ShaderLib.js b/src/renderers/shaders/ShaderLib.js index 4b64670e4f8bfb..1cdc41b72aa5af 100644 --- a/src/renderers/shaders/ShaderLib.js +++ b/src/renderers/shaders/ShaderLib.js @@ -77,22 +77,28 @@ THREE.ShaderLib = { "void main() {", - " gl_FragColor = vec4( diffuse, opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], - THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], + + " outgoingLight = diffuseColor.rgb;", // simple shader + + THREE.ShaderChunk[ "lightmap_fragment" ], // TODO: Light map on an otherwise unlit surface doesn't make sense. THREE.ShaderChunk[ "envmap_fragment" ], - THREE.ShaderChunk[ "shadowmap_fragment" ], + THREE.ShaderChunk[ "shadowmap_fragment" ], // TODO: Shadows on an otherwise unlit surface doesn't make sense. THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -165,6 +171,8 @@ THREE.ShaderLib = { fragmentShader: [ + "uniform vec3 diffuse;", + "uniform vec3 emissive;", "uniform float opacity;", "varying vec3 vLightFront;", @@ -188,10 +196,12 @@ THREE.ShaderLib = { "void main() {", - " gl_FragColor = vec4( vec3( 1.0 ), opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], @@ -202,18 +212,17 @@ THREE.ShaderLib = { //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", " if ( gl_FrontFacing )", - " gl_FragColor.xyz *= vLightFront;", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", " else", - " gl_FragColor.xyz *= vLightBack;", + " outgoingLight += diffuseColor.rgb * vLightBack + emissive;", " #else", - " gl_FragColor.xyz *= vLightFront;", + " outgoingLight += diffuseColor.rgb * vLightFront + emissive;", " #endif", THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], @@ -221,6 +230,8 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -252,7 +263,12 @@ THREE.ShaderLib = { "#define PHONG", "varying vec3 vViewPosition;", - "varying vec3 vNormal;", + + "#ifndef FLAT_SHADED", + + " varying vec3 vNormal;", + + "#endif", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "map_pars_vertex" ], @@ -276,8 +292,12 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], + "#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED + " vNormal = normalize( transformedNormal );", + "#endif", + THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "default_vertex" ], @@ -299,11 +319,10 @@ THREE.ShaderLib = { "#define PHONG", "uniform vec3 diffuse;", - "uniform float opacity;", - "uniform vec3 emissive;", "uniform vec3 specular;", "uniform float shininess;", + "uniform float opacity;", THREE.ShaderChunk[ "common" ], THREE.ShaderChunk[ "color_pars_fragment" ], @@ -321,10 +340,12 @@ THREE.ShaderLib = { "void main() {", - " gl_FragColor = vec4( vec3( 1.0 ), opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_fragment" ], + THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "alphamap_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], @@ -332,7 +353,6 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "lights_phong_fragment" ], THREE.ShaderChunk[ "lightmap_fragment" ], - THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], @@ -340,6 +360,8 @@ THREE.ShaderLib = { THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -401,15 +423,21 @@ THREE.ShaderLib = { "void main() {", - " gl_FragColor = vec4( psColor, opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( psColor, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "map_particle_fragment" ], - THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "color_fragment" ], + THREE.ShaderChunk[ "alphatest_fragment" ], + + " outgoingLight = diffuseColor.rgb;", // simple shader + THREE.ShaderChunk[ "shadowmap_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -480,12 +508,18 @@ THREE.ShaderLib = { " }", - " gl_FragColor = vec4( diffuse, opacity );", + " vec3 outgoingLight = vec3( 0.0 );", // outgoing light does not have an alpha, the surface does + " vec4 diffuseColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], THREE.ShaderChunk[ "color_fragment" ], + + " outgoingLight = diffuseColor.rgb;", // simple shader + THREE.ShaderChunk[ "fog_fragment" ], + " gl_FragColor = vec4( outgoingLight, diffuseColor.a );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects + "}" ].join("\n") @@ -542,7 +576,7 @@ THREE.ShaderLib = { " #endif", " float color = 1.0 - smoothstep( mNear, mFar, depth );", - " gl_FragColor = vec4( vec3( color ), opacity );", + " gl_FragColor = vec4( vec3( color ), opacity );", // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects "}" @@ -692,7 +726,7 @@ THREE.ShaderLib = { "vec3 direction = normalize( vWorldPosition );", "vec2 sampleUV;", "sampleUV.y = saturate( tFlip * direction.y * -0.5 + 0.5 );", - "sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;", + "sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;", "gl_FragColor = texture2D( tEquirect, sampleUV );", THREE.ShaderChunk[ "logdepthbuf_fragment" ], diff --git a/src/renderers/shaders/UniformsLib.js b/src/renderers/shaders/UniformsLib.js index 135925fa1f3bf1..87da6d67c82623 100644 --- a/src/renderers/shaders/UniformsLib.js +++ b/src/renderers/shaders/UniformsLib.js @@ -61,13 +61,15 @@ THREE.UniformsLib = { "pointLightColor" : { type: "fv", value: [] }, "pointLightPosition" : { type: "fv", value: [] }, "pointLightDistance" : { type: "fv1", value: [] }, + "pointLightDecay" : { type: "fv1", value: [] }, "spotLightColor" : { type: "fv", value: [] }, "spotLightPosition" : { type: "fv", value: [] }, "spotLightDirection" : { type: "fv", value: [] }, "spotLightDistance" : { type: "fv1", value: [] }, "spotLightAngleCos" : { type: "fv1", value: [] }, - "spotLightExponent" : { type: "fv1", value: [] } + "spotLightExponent" : { type: "fv1", value: [] }, + "spotLightDecay" : { type: "fv1", value: [] } }, @@ -78,6 +80,7 @@ THREE.UniformsLib = { "size" : { type: "f", value: 1.0 }, "scale" : { type: "f", value: 1.0 }, "map" : { type: "t", value: null }, + "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, "fogDensity" : { type: "f", value: 0.00025 }, "fogNear" : { type: "f", value: 1 }, diff --git a/src/renderers/webgl/WebGLExtensions.js b/src/renderers/webgl/WebGLExtensions.js index f9c154c18cbcd9..79b801a8e8b03b 100644 --- a/src/renderers/webgl/WebGLExtensions.js +++ b/src/renderers/webgl/WebGLExtensions.js @@ -37,7 +37,7 @@ THREE.WebGLExtensions = function ( gl ) { if ( extension === null ) { - console.log( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); + THREE.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); } diff --git a/src/renderers/webgl/WebGLProgram.js b/src/renderers/webgl/WebGLProgram.js index 7301f3dbea59dc..e57ad9ced43401 100644 --- a/src/renderers/webgl/WebGLProgram.js +++ b/src/renderers/webgl/WebGLProgram.js @@ -135,6 +135,8 @@ THREE.WebGLProgram = ( function () { } + var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; + // console.log( 'building new program ' ); // @@ -165,6 +167,7 @@ THREE.WebGLProgram = ( function () { _this.gammaInput ? '#define GAMMA_INPUT' : '', _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, '#define MAX_DIR_LIGHTS ' + parameters.maxDirLights, '#define MAX_POINT_LIGHTS ' + parameters.maxPointLights, @@ -185,6 +188,8 @@ THREE.WebGLProgram = ( function () { parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.vertexColors ? '#define USE_COLOR' : '', + parameters.flatShading ? '#define FLAT_SHADED': '', + parameters.skinning ? '#define USE_SKINNING' : '', parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', @@ -264,7 +269,7 @@ THREE.WebGLProgram = ( function () { 'precision ' + parameters.precision + ' float;', 'precision ' + parameters.precision + ' int;', - ( parameters.bumpMap || parameters.normalMap ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( parameters.bumpMap || parameters.normalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', customDefines, @@ -275,10 +280,11 @@ THREE.WebGLProgram = ( function () { '#define MAX_SHADOWS ' + parameters.maxShadows, - parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest: '', + parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest : '', _this.gammaInput ? '#define GAMMA_INPUT' : '', _this.gammaOutput ? '#define GAMMA_OUTPUT' : '', + '#define GAMMA_FACTOR ' + gammaFactorDefine, ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', @@ -295,6 +301,8 @@ THREE.WebGLProgram = ( function () { parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.vertexColors ? '#define USE_COLOR' : '', + parameters.flatShading ? '#define FLAT_SHADED': '', + parameters.metal ? '#define METAL' : '', parameters.wrapAround ? '#define WRAP_AROUND' : '', parameters.doubleSided ? '#define DOUBLE_SIDED' : '', @@ -334,19 +342,19 @@ THREE.WebGLProgram = ( function () { _gl.linkProgram( program ); + var programLogInfo = _gl.getProgramInfoLog( program ); + if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { - console.error( 'THREE.WebGLProgram: Could not initialise shader.' ); - console.error( 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) ); - console.error( 'gl.getError()', _gl.getError() ); + THREE.error( 'THREE.WebGLProgram: shader error: ' + _gl.getError(), 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ), 'gl.getPRogramInfoLog', programLogInfo ); } - if ( _gl.getProgramInfoLog( program ) !== '' ) { + if ( programLogInfo !== '' ) { - console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', _gl.getProgramInfoLog( program ) ); - // console.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); - // console.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); + THREE.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()' + programLogInfo ); + // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); + // THREE.warn( _gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); } diff --git a/src/renderers/webgl/WebGLShader.js b/src/renderers/webgl/WebGLShader.js index 0948a6997b4850..a6c1abbf8789cd 100644 --- a/src/renderers/webgl/WebGLShader.js +++ b/src/renderers/webgl/WebGLShader.js @@ -23,14 +23,13 @@ THREE.WebGLShader = ( function () { if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) { - console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); + THREE.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); } if ( gl.getShaderInfoLog( shader ) !== '' ) { - console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ) ); - console.warn( addLineNumbers( string ) ); + THREE.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); } diff --git a/src/renderers/webgl/WebGLState.js b/src/renderers/webgl/WebGLState.js new file mode 100644 index 00000000000000..ef0d534941e51f --- /dev/null +++ b/src/renderers/webgl/WebGLState.js @@ -0,0 +1,293 @@ +/** +* @author mrdoob / http://mrdoob.com/ +*/ + +THREE.WebGLState = function ( gl, paramThreeToGL ) { + + var newAttributes = new Uint8Array( 16 ); + var enabledAttributes = new Uint8Array( 16 ); + + var currentBlending = null; + var currentBlendEquation = null; + var currentBlendSrc = null; + var currentBlendDst = null; + var currentBlendEquationAlpha = null; + var currentBlendSrcAlpha = null; + var currentBlendDstAlpha = null; + + var currentDepthTest = null; + var currentDepthWrite = null; + + var currentColorWrite = null; + + var currentDoubleSided = null; + var currentFlipSided = null; + + var currentLineWidth = null; + + var currentPolygonOffset = null; + var currentPolygonOffsetFactor = null; + var currentPolygonOffsetUnits = null; + + this.initAttributes = function () { + + for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { + + newAttributes[ i ] = 0; + + } + + }; + + this.enableAttribute = function ( attribute ) { + + newAttributes[ attribute ] = 1; + + if ( enabledAttributes[ attribute ] === 0 ) { + + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; + + } + + }; + + this.disableUnusedAttributes = function () { + + for ( var i = 0, l = enabledAttributes.length; i < l; i ++ ) { + + if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { + + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; + + } + + } + + }; + + this.setBlending = function ( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha ) { + + if ( blending !== currentBlending ) { + + 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 ); + + } + + currentBlending = blending; + + } + + if ( blending === THREE.CustomBlending ) { + + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; + + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { + + gl.blendEquationSeparate( paramThreeToGL( blendEquation ), paramThreeToGL( blendEquationAlpha ) ); + + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; + + } + + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { + + gl.blendFuncSeparate( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ), paramThreeToGL( blendSrcAlpha ), paramThreeToGL( blendDstAlpha ) ); + + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; + + } + + } else { + + currentBlendEquation = null; + currentBlendSrc = null; + currentBlendDst = null; + currentBlendEquationAlpha = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; + + } + + }; + + this.setDepthTest = function ( depthTest ) { + + if ( currentDepthTest !== depthTest ) { + + if ( depthTest ) { + + gl.enable( gl.DEPTH_TEST ); + + } else { + + gl.disable( gl.DEPTH_TEST ); + + } + + currentDepthTest = depthTest; + + } + + }; + + this.setDepthWrite = function ( depthWrite ) { + + if ( currentDepthWrite !== depthWrite ) { + + gl.depthMask( depthWrite ); + currentDepthWrite = depthWrite; + + } + + }; + + this.setColorWrite = function ( colorWrite ) { + + if ( currentColorWrite !== colorWrite ) { + + gl.colorMask( colorWrite, colorWrite, colorWrite, colorWrite ); + currentColorWrite = colorWrite; + + } + + }; + + this.setDoubleSided = function ( doubleSided ) { + + if ( currentDoubleSided !== doubleSided ) { + + if ( doubleSided ) { + + gl.disable( gl.CULL_FACE ); + + } else { + + gl.enable( gl.CULL_FACE ); + + } + + currentDoubleSided = doubleSided; + + } + + }; + + this.setFlipSided = function ( flipSided ) { + + if ( currentFlipSided !== flipSided ) { + + if ( flipSided ) { + + gl.frontFace( gl.CW ); + + } else { + + gl.frontFace( gl.CCW ); + + } + + currentFlipSided = flipSided; + + } + + }; + + this.setLineWidth = function ( width ) { + + if ( width !== currentLineWidth ) { + + gl.lineWidth( width ); + + currentLineWidth = width; + + } + + }; + + this.setPolygonOffset = function ( polygonoffset, factor, units ) { + + if ( currentPolygonOffset !== polygonoffset ) { + + if ( polygonoffset ) { + + gl.enable( gl.POLYGON_OFFSET_FILL ); + + } else { + + gl.disable( gl.POLYGON_OFFSET_FILL ); + + } + + currentPolygonOffset = polygonoffset; + + } + + if ( polygonoffset && ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) ) { + + gl.polygonOffset( factor, units ); + + currentPolygonOffsetFactor = factor; + currentPolygonOffsetUnits = units; + + } + + }; + + this.reset = function () { + + for ( var i = 0; i < enabledAttributes.length; i ++ ) { + + enabledAttributes[ i ] = 0; + + } + + currentBlending = null; + currentDepthTest = null; + currentDepthWrite = null; + currentColorWrite = null; + currentDoubleSided = null; + currentFlipSided = null; + + }; + +}; diff --git a/src/renderers/webgl/WebGLTextures.js b/src/renderers/webgl/WebGLTextures.js new file mode 100644 index 00000000000000..36527cc9d0d069 --- /dev/null +++ b/src/renderers/webgl/WebGLTextures.js @@ -0,0 +1,41 @@ +/** +* @author mrdoob / http://mrdoob.com/ +*/ + +THREE.WebGLTextures = function ( gl ) { + + var textures = {}; + + this.get = function ( texture ) { + + if ( textures[ texture.id ] !== undefined ) { + + return textures[ texture.id ]; + + } + + return this.create( texture ); + + }; + + this.create = function ( texture ) { + + texture.addEventListener( 'dispose', this.delete ); + + textures[ texture.id ] = gl.createTexture(); + + return textures[ texture.id ]; + + }; + + this.delete = function ( texture ) { + + texture.removeEventListener( 'dispose', this.delete ); + + gl.deleteTexture( textures[ texture.id ] ); + + delete textures[ texture.id ]; + + }; + +}; diff --git a/src/renderers/webgl/plugins/LensFlarePlugin.js b/src/renderers/webgl/plugins/LensFlarePlugin.js index d1c3a7b593e224..3368fadcbf019d 100644 --- a/src/renderers/webgl/plugins/LensFlarePlugin.js +++ b/src/renderers/webgl/plugins/LensFlarePlugin.js @@ -321,7 +321,7 @@ THREE.LensFlarePlugin = function ( renderer, flares ) { // calc object screen position var flare = flares[ i ]; - + tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); tempPosition.applyMatrix4( camera.matrixWorldInverse ); @@ -419,7 +419,7 @@ THREE.LensFlarePlugin = function ( renderer, flares ) { 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.state.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); renderer.setTexture( sprite.texture, 1 ); gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); diff --git a/src/renderers/webgl/plugins/ShadowMapPlugin.js b/src/renderers/webgl/plugins/ShadowMapPlugin.js index 82eac2d8d1fac2..a5b8e25eaea57a 100644 --- a/src/renderers/webgl/plugins/ShadowMapPlugin.js +++ b/src/renderers/webgl/plugins/ShadowMapPlugin.js @@ -15,7 +15,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje _max = new THREE.Vector3(), _matrixPosition = new THREE.Vector3(), - + _renderList = []; // init @@ -63,7 +63,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje var i, il, j, jl, n, shadowMap, shadowMatrix, shadowCamera, - program, buffer, material, + buffer, material, webglObject, object, light, lights = [], @@ -89,7 +89,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje } - _renderer.setDepthTest( true ); + _renderer.state.setDepthTest( true ); // preprocess lights // - skip lights that are not casting shadows @@ -122,7 +122,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje light.shadowCascadeArray[ n ] = virtualLight; - console.log( "Created virtualLight", virtualLight ); + //console.log( "Created virtualLight", virtualLight ); } else { @@ -183,7 +183,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje } else { - console.error( "Unsupported light type for shadow" ); + THREE.error( "THREE.ShadowMapPlugin: Unsupported light type for shadow", light ); continue; } @@ -348,7 +348,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje }; - function projectObject( scene, object, shadowCamera ){ + function projectObject( scene, object, shadowCamera ) { if ( object.visible ) { diff --git a/src/renderers/webgl/plugins/SpritePlugin.js b/src/renderers/webgl/plugins/SpritePlugin.js index 704c977559c88e..7212d1216279af 100644 --- a/src/renderers/webgl/plugins/SpritePlugin.js +++ b/src/renderers/webgl/plugins/SpritePlugin.js @@ -214,9 +214,9 @@ THREE.SpritePlugin = function ( renderer, sprites ) { 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 ); + renderer.state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); + renderer.state.setDepthTest( material.depthTest ); + renderer.state.setDepthWrite( material.depthWrite ); if ( material.map && material.map.image && material.map.image.width ) { diff --git a/src/textures/Texture.js b/src/textures/Texture.js index dd2d513eda379f..231f71a55a6418 100644 --- a/src/textures/Texture.js +++ b/src/textures/Texture.js @@ -11,6 +11,7 @@ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, f this.uuid = THREE.Math.generateUUID(); this.name = ''; + this.sourceFile = ''; this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE; this.mipmaps = []; diff --git a/test/unit/math/Math.js b/test/unit/math/Math.js new file mode 100644 index 00000000000000..24fab739537df9 --- /dev/null +++ b/test/unit/math/Math.js @@ -0,0 +1,35 @@ +/** + * @author humbletim / https://github.com/humbletim + */ + +module( "Math" ); + +//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign +//http://people.mozilla.org/~jorendorff/es6-draft.html#sec-math.sign +/* +20.2.2.29 Math.sign(x) + +Returns the sign of the x, indicating whether x is positive, negative or zero. + +If x is NaN, the result is NaN. +If x is -0, the result is -0. +If x is +0, the result is +0. +If x is negative and not -0, the result is -1. +If x is positive and not +0, the result is +1. +*/ + +test( "Math.sign/polyfill", function() { + + ok( isNaN( Math.sign(NaN) ) , "If x is NaN, the result is NaN."); + ok( isNaN( Math.sign(new THREE.Vector3()) ) , "If x is NaN, the result is NaN."); + ok( isNaN( Math.sign() ) , "If x is NaN, the result is NaN."); + ok( isNaN( Math.sign('--3') ) , "If x is NaN<'--3'>, the result is NaN."); + ok( Math.sign(-0) === -0 , "If x is -0, the result is -0."); + ok( Math.sign(+0) === +0 , "If x is +0, the result is +0."); + ok( Math.sign(-Infinity) === -1 , "If x is negative<-Infinity> and not -0, the result is -1."); + ok( Math.sign('-3') === -1 , "If x is negative<'-3'> and not -0, the result is -1."); + ok( Math.sign('-1e-10') === -1 , "If x is negative<'-1e-10'> and not -0, the result is -1."); + ok( Math.sign(+Infinity) === +1 , "If x is positive<+Infinity> and not +0, the result is +1."); + ok( Math.sign('+3') === +1 , "If x is positive<'+3'> and not +0, the result is +1."); + +}); diff --git a/test/unit/unittests_sources.html b/test/unit/unittests_sources.html index 82aabde1e81459..c92a60d9550926 100644 --- a/test/unit/unittests_sources.html +++ b/test/unit/unittests_sources.html @@ -45,6 +45,7 @@ + diff --git a/test/unit/unittests_three-math.html b/test/unit/unittests_three-math.html index 7bd8ac804f271f..5eaf7e6388e7ef 100644 --- a/test/unit/unittests_three-math.html +++ b/test/unit/unittests_three-math.html @@ -28,6 +28,7 @@ + diff --git a/test/unit/unittests_three.html b/test/unit/unittests_three.html index b02c16bec56ff9..e995d3025c5f5e 100644 --- a/test/unit/unittests_three.html +++ b/test/unit/unittests_three.html @@ -28,6 +28,7 @@ + diff --git a/test/unit/unittests_three.min.html b/test/unit/unittests_three.min.html index 5635fc5a0f5a95..34168123d13212 100644 --- a/test/unit/unittests_three.min.html +++ b/test/unit/unittests_three.min.html @@ -28,6 +28,7 @@ + diff --git a/utils/build/build.js b/utils/build/build.js index 036e1191925e4c..9974610636aed7 100644 --- a/utils/build/build.js +++ b/utils/build/build.js @@ -1,7 +1,7 @@ var fs = require("fs"); var path = require("path"); var argparse = require( "argparse" ); -var uglify = require("uglify-js2"); +var uglify = require("uglify-js"); var spawn = require('child_process').spawn; function main() { @@ -14,7 +14,7 @@ function main() { parser.addArgument( ['--amd'], { action: 'storeTrue', defaultValue: false } ); parser.addArgument( ['--minify'], { action: 'storeTrue', defaultValue: false } ); parser.addArgument( ['--output'], { defaultValue: '../../build/three.js' } ); - parser.addArgument( ['--sourcemaps'], { action: 'storeTrue', defaultValue: false } ); + parser.addArgument( ['--sourcemaps'], { action: 'storeTrue', defaultValue: true } ); var args = parser.parseArgs(); @@ -28,13 +28,13 @@ function main() { if ( args.sourcemaps ){ sourcemap = output + '.map'; - sourcemapping = '\n//@ sourceMappingURL=' + sourcemap; + sourcemapping = '\n//# sourceMappingURL=three.min.js.map'; } var buffer = []; - var sources = []; - + var sources = []; // used for source maps with minification + if ( args.amd ){ buffer.push('function ( root, factory ) {\n\n\tif ( typeof define === \'function\' && define.amd ) {\n\n\t\tdefine( [ \'exports\' ], factory );\n\n\t} else if ( typeof exports === \'object\' ) {\n\n\t\tfactory( exports );\n\n\t} else {\n\n\t\tfactory( root );\n\n\t}\n\n}( this, function ( exports ) {\n\n'); }; @@ -50,17 +50,20 @@ function main() { buffer.push('// File:' + files[ j ]); buffer.push('\n\n'); + + contents = fs.readFileSync( file, 'utf8' ); + if( file.indexOf( '.glsl') >= 0 ) { - buffer.push('THREE.ShaderChunk[\'' + path.basename(file, '.glsl') + '\'] = "'); - buffer.push(fs.readFileSync( file, 'utf8' )); - buffer.push('";\n\n'); - } - else { - sources.push( file ); - buffer.push( fs.readFileSync( file, 'utf8' ) ); - buffer.push('\n'); + + contents = 'THREE.ShaderChunk[ \'' + + path.basename( file, '.glsl' ) + '\' ] =' + + JSON.stringify( contents ) + ';\n'; + } + sources.push( { file: file, contents: contents } ); + buffer.push( contents ); + buffer.push( '\n' ); } } @@ -73,17 +76,60 @@ function main() { if ( !args.minify ){ - fs.writeFileSync( output,temp, 'utf8' ); + fs.writeFileSync( output, temp, 'utf8' ); } else { - var result = uglify.minify( sources, { outSourceMap: sourcemap } ); - - fs.writeFileSync( output, '// threejs.org/license\n' + result.code + sourcemapping, 'utf8' ); + var LICENSE = "threejs.org/license"; + + // Parsing + + var toplevel = null; + + toplevel = uglify.parse( '// ' + LICENSE + '\n' ); + + sources.forEach( function( source ) { + + toplevel = uglify.parse( source.contents, { + filename: source.file, + toplevel: toplevel + } ); + + } ); + + // Compression + + toplevel.figure_out_scope(); + var compressor = uglify.Compressor( {} ); + var compressed_ast = toplevel.transform( compressor ); + + // Mangling + + compressed_ast.figure_out_scope(); + compressed_ast.compute_char_frequency(); + compressed_ast.mangle_names(); + + // Output + + var source_map_options = { + file: 'three.min.js', + root: 'src' + }; + + var source_map = uglify.SourceMap( source_map_options ) + var stream = uglify.OutputStream( { + source_map: source_map, + comments: new RegExp( LICENSE ) + } ); + + compressed_ast.print( stream ); + var code = stream.toString(); + + fs.writeFileSync( output, code + sourcemapping, 'utf8' ); if ( args.sourcemaps ) { - fs.writeFileSync( sourcemap, result.map, 'utf8' ); + fs.writeFileSync( sourcemap, source_map.toString(), 'utf8' ); } diff --git a/utils/build/includes/common.json b/utils/build/includes/common.json index f6b9992cda2705..5bbc980316ece5 100644 --- a/utils/build/includes/common.json +++ b/utils/build/includes/common.json @@ -25,6 +25,7 @@ "src/core/Face3.js", "src/core/Face4.js", "src/core/BufferAttribute.js", + "src/core/DynamicBufferAttribute.js", "src/core/BufferGeometry.js", "src/core/Geometry.js", "src/cameras/Camera.js", @@ -145,6 +146,7 @@ "src/renderers/webgl/WebGLExtensions.js", "src/renderers/webgl/WebGLProgram.js", "src/renderers/webgl/WebGLShader.js", + "src/renderers/webgl/WebGLState.js", "src/renderers/webgl/plugins/LensFlarePlugin.js", "src/renderers/webgl/plugins/ShadowMapPlugin.js", "src/renderers/webgl/plugins/SpritePlugin.js" diff --git a/utils/build/package.json b/utils/build/package.json index c5aa6e818b14ee..b465eb34e4d2d6 100644 --- a/utils/build/package.json +++ b/utils/build/package.json @@ -9,8 +9,8 @@ }, "devDependencies": { - "uglify-js2": "*", - "argparse" : "*" + "uglify-js": "^2.4.17", + "argparse" : "*" }, "repository" : { diff --git a/utils/editors/sublime.py b/utils/editors/sublime.py deleted file mode 100644 index ce232456dc1cdb..00000000000000 --- a/utils/editors/sublime.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python - -import sys - -if sys.version_info < (2, 7): - print("This script requires at least Python 2.7.") - print("Please, update to a newer version: http://www.python.org/download/releases/") - exit() - -import argparse -import json -import os -import re -import shutil -import tempfile - - -def main(argv=None): - - parser = argparse.ArgumentParser() - parser.add_argument('--include', action='append', required=True) - parser.add_argument('--output', default='sublimetext2/threejs.sublime-completions') - - args = parser.parse_args() - - output = args.output - - # parsing - - print(' * Generating ' + output) - - fd, path = tempfile.mkstemp() - tmp = open(path, 'w') - tmp.write('{\n\t"scope": "source.js,source.js.embedded.html,source.coffee",\n\t"version": "r55",\n\t"completions":\n\t[\n') - - for include in args.include: - with open('../build/includes/' + include + '.json','r') as f: files = json.load(f) - for filename in files: - filename = '../../' + filename; - with open(filename, 'r') as f: - string = f.read() - match = re.search('THREE.(\w+)[\ ]+?=[\ ]+?function[\ ]+\(([\w\,\ ]+)?\)', string) - if match: - name = match.group(1) - parameters = match.group(2) - if parameters is None: - parameters = '' - else: - array = parameters.split( ',' ) - for i in range(len(array)): - array[i] = '${'+str(i+1)+':'+array[i].strip()+'}' # ${1:param} - parameters = ' '+', '.join(array)+' ' - tmp.write('\t\t{ "trigger": "THREE.'+name+'", "contents": "THREE.'+name+'('+parameters+')$0" },\n' ) - - tmp.write("\t\t\"THREE\"\n\t]\n}") - tmp.close() - - # save - - shutil.copy(path, output) - os.chmod(output, 0o664); # temp files would usually get 0600 - - -if __name__ == "__main__": - main() diff --git a/utils/editors/sublime.sh b/utils/editors/sublime.sh deleted file mode 100755 index 02d8d999366aad..00000000000000 --- a/utils/editors/sublime.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -python sublime.py --include common --include extras --output sublimetext2/threejs.sublime-completions diff --git a/utils/editors/sublimetext2/README.md b/utils/editors/sublimetext2/README.md deleted file mode 100644 index 518cf9d0cc1d33..00000000000000 --- a/utils/editors/sublimetext2/README.md +++ /dev/null @@ -1,9 +0,0 @@ -### How to install - -1. Compress `threejs.sublime-completions` into `threejs.sublime-package`. - -```shell -zip threejs.sublime-package threejs.sublime-completions -``` - -2. Copy the compressed file into `Sublime Text 2/Pristine Packages`. diff --git a/utils/editors/sublimetext2/threejs.sublime-completions b/utils/editors/sublimetext2/threejs.sublime-completions deleted file mode 100644 index a0fcc117694c36..00000000000000 --- a/utils/editors/sublimetext2/threejs.sublime-completions +++ /dev/null @@ -1,143 +0,0 @@ -{ - "scope": "source.js,source.js.embedded.html,source.coffee,source.ts", - "version": "r55", - "completions": - [ - { "trigger": "THREE.extend", "contents": "THREE.extend( ${1:obj}, ${2:source} )$0" }, - { "trigger": "THREE.Color", "contents": "THREE.Color( ${1:value} )$0" }, - { "trigger": "THREE.Quaternion", "contents": "THREE.Quaternion( ${1:x}, ${2:y}, ${3:z}, ${4:w} )$0" }, - { "trigger": "THREE.Vector2", "contents": "THREE.Vector2( ${1:x}, ${2:y} )$0" }, - { "trigger": "THREE.Vector3", "contents": "THREE.Vector3( ${1:x}, ${2:y}, ${3:z} )$0" }, - { "trigger": "THREE.Vector4", "contents": "THREE.Vector4( ${1:x}, ${2:y}, ${3:z}, ${4:w} )$0" }, - { "trigger": "THREE.Euler", "contents": "THREE.Euler( ${1:x}, ${2:y}, ${3:z}, ${4:order} )$0" }, - { "trigger": "THREE.Line3", "contents": "THREE.Line3( ${1:start}, ${2:end} )$0" }, - { "trigger": "THREE.Box2", "contents": "THREE.Box2( ${1:min}, ${2:max} )$0" }, - { "trigger": "THREE.Box3", "contents": "THREE.Box3( ${1:min}, ${2:max} )$0" }, - { "trigger": "THREE.Matrix3", "contents": "THREE.Matrix3( ${1:n11}, ${2:n12}, ${3:n13}, ${4:n21}, ${5:n22}, ${6:n23}, ${7:n31}, ${8:n32}, ${9:n33} )$0" }, - { "trigger": "THREE.Matrix4", "contents": "THREE.Matrix4( ${1:n11}, ${2:n12}, ${3:n13}, ${4:n14}, ${5:n21}, ${6:n22}, ${7:n23}, ${8:n24}, ${9:n31}, ${10:n32}, ${11:n33}, ${12:n34}, ${13:n41}, ${14:n42}, ${15:n43}, ${16:n44} )$0" }, - { "trigger": "THREE.Ray", "contents": "THREE.Ray( ${1:origin}, ${2:direction} )$0" }, - { "trigger": "THREE.Sphere", "contents": "THREE.Sphere( ${1:center}, ${2:radius} )$0" }, - { "trigger": "THREE.Frustum", "contents": "THREE.Frustum( ${1:p0}, ${2:p1}, ${3:p2}, ${4:p3}, ${5:p4}, ${6:p5} )$0" }, - { "trigger": "THREE.Plane", "contents": "THREE.Plane( ${1:normal}, ${2:constant} )$0" }, - { "trigger": "THREE.Spline", "contents": "THREE.Spline( ${1:points} )$0" }, - { "trigger": "THREE.Triangle", "contents": "THREE.Triangle( ${1:a}, ${2:b}, ${3:c} )$0" }, - { "trigger": "THREE.Vertex", "contents": "THREE.Vertex( ${1:v} )$0" }, - { "trigger": "THREE.UV", "contents": "THREE.UV( ${1:u}, ${2:v} )$0" }, - { "trigger": "THREE.Clock", "contents": "THREE.Clock( ${1:autoStart} )$0" }, - { "trigger": "THREE.EventDispatcher", "contents": "THREE.EventDispatcher()$0" }, - { "trigger": "THREE.Raycaster", "contents": "THREE.Raycaster( ${1:origin}, ${2:direction}, ${3:near}, ${4:far} )$0" }, - { "trigger": "THREE.Object3D", "contents": "THREE.Object3D()$0" }, - { "trigger": "THREE.Projector", "contents": "THREE.Projector()$0" }, - { "trigger": "THREE.Face3", "contents": "THREE.Face3( ${1:a}, ${2:b}, ${3:c}, ${4:normal}, ${5:color}, ${6:materialIndex} )$0" }, - { "trigger": "THREE.Face4", "contents": "THREE.Face4( ${1:a}, ${2:b}, ${3:c}, ${4:d}, ${5:normal}, ${6:color}, ${7:materialIndex} )$0" }, - { "trigger": "THREE.Geometry", "contents": "THREE.Geometry()$0" }, - { "trigger": "THREE.BufferGeometry", "contents": "THREE.BufferGeometry()$0" }, - { "trigger": "THREE.Camera", "contents": "THREE.Camera()$0" }, - { "trigger": "THREE.OrthographicCamera", "contents": "THREE.OrthographicCamera( ${1:left}, ${2:right}, ${3:top}, ${4:bottom}, ${5:near}, ${6:far} )$0" }, - { "trigger": "THREE.PerspectiveCamera", "contents": "THREE.PerspectiveCamera( ${1:fov}, ${2:aspect}, ${3:near}, ${4:far} )$0" }, - { "trigger": "THREE.Light", "contents": "THREE.Light( ${1:hex} )$0" }, - { "trigger": "THREE.AmbientLight", "contents": "THREE.AmbientLight( ${1:hex} )$0" }, - { "trigger": "THREE.AreaLight", "contents": "THREE.AreaLight( ${1:hex}, ${2:intensity} )$0" }, - { "trigger": "THREE.DirectionalLight", "contents": "THREE.DirectionalLight( ${1:hex}, ${2:intensity} )$0" }, - { "trigger": "THREE.HemisphereLight", "contents": "THREE.HemisphereLight( ${1:skyColorHex}, ${2:groundColorHex}, ${3:intensity} )$0" }, - { "trigger": "THREE.PointLight", "contents": "THREE.PointLight( ${1:hex}, ${2:intensity}, ${3:distance} )$0" }, - { "trigger": "THREE.SpotLight", "contents": "THREE.SpotLight( ${1:hex}, ${2:intensity}, ${3:distance}, ${4:angle}, ${5:exponent} )$0" }, - { "trigger": "THREE.Loader", "contents": "THREE.Loader( ${1:showStatus} )$0" }, - { "trigger": "THREE.XHRLoader", "contents": "THREE.XHRLoader( ${1:manager} )$0" }, - { "trigger": "THREE.ImageLoader", "contents": "THREE.ImageLoader( ${1:manager} )$0" }, - { "trigger": "THREE.JSONLoader", "contents": "THREE.JSONLoader( ${1:showStatus} )$0" }, - { "trigger": "THREE.LoadingManager", "contents": "THREE.LoadingManager( ${1:onLoad}, ${2:onProgress}, ${3:onError} )$0" }, - { "trigger": "THREE.BufferGeometryLoader", "contents": "THREE.BufferGeometryLoader( ${1:manager} )$0" }, - { "trigger": "THREE.GeometryLoader", "contents": "THREE.GeometryLoader( ${1:manager} )$0" }, - { "trigger": "THREE.MaterialLoader", "contents": "THREE.MaterialLoader( ${1:manager} )$0" }, - { "trigger": "THREE.ObjectLoader", "contents": "THREE.ObjectLoader( ${1:manager} )$0" }, - { "trigger": "THREE.SceneLoader", "contents": "THREE.SceneLoader()$0" }, - { "trigger": "THREE.TextureLoader", "contents": "THREE.TextureLoader( ${1:manager} )$0" }, - { "trigger": "THREE.Material", "contents": "THREE.Material()$0" }, - { "trigger": "THREE.LineBasicMaterial", "contents": "THREE.LineBasicMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.LineDashedMaterial", "contents": "THREE.LineDashedMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.MeshBasicMaterial", "contents": "THREE.MeshBasicMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.MeshLambertMaterial", "contents": "THREE.MeshLambertMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.MeshPhongMaterial", "contents": "THREE.MeshPhongMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.MeshDepthMaterial", "contents": "THREE.MeshDepthMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.MeshNormalMaterial", "contents": "THREE.MeshNormalMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.MeshFaceMaterial", "contents": "THREE.MeshFaceMaterial( ${1:materials} )$0" }, - { "trigger": "THREE.ParticleBasicMaterial", "contents": "THREE.ParticleBasicMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.ParticleCanvasMaterial", "contents": "THREE.ParticleCanvasMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.ShaderMaterial", "contents": "THREE.ShaderMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.SpriteMaterial", "contents": "THREE.SpriteMaterial( ${1:parameters} )$0" }, - { "trigger": "THREE.Texture", "contents": "THREE.Texture( ${1:image}, ${2:mapping}, ${3:wrapS}, ${4:wrapT}, ${5:magFilter}, ${6:minFilter}, ${7:format}, ${8:type}, ${9:anisotropy} )$0" }, - { "trigger": "THREE.CompressedTexture", "contents": "THREE.CompressedTexture( ${1:mipmaps}, ${2:width}, ${3:height}, ${4:format}, ${5:type}, ${6:mapping}, ${7:wrapS}, ${8:wrapT}, ${9:magFilter}, ${10:minFilter}, ${11:anisotropy} )$0" }, - { "trigger": "THREE.DataTexture", "contents": "THREE.DataTexture( ${1:data}, ${2:width}, ${3:height}, ${4:format}, ${5:type}, ${6:mapping}, ${7:wrapS}, ${8:wrapT}, ${9:magFilter}, ${10:minFilter}, ${11:anisotropy} )$0" }, - { "trigger": "THREE.Particle", "contents": "THREE.Particle( ${1:material} )$0" }, - { "trigger": "THREE.ParticleSystem", "contents": "THREE.ParticleSystem( ${1:geometry}, ${2:material} )$0" }, - { "trigger": "THREE.Line", "contents": "THREE.Line( ${1:geometry}, ${2:material}, ${3:type} )$0" }, - { "trigger": "THREE.Mesh", "contents": "THREE.Mesh( ${1:geometry}, ${2:material} )$0" }, - { "trigger": "THREE.SkinnedMesh", "contents": "THREE.SkinnedMesh( ${1:geometry}, ${2:material}, ${3:useVertexTexture} )$0" }, - { "trigger": "THREE.MorphAnimMesh", "contents": "THREE.MorphAnimMesh( ${1:geometry}, ${2:material} )$0" }, - { "trigger": "THREE.LOD", "contents": "THREE.LOD()$0" }, - { "trigger": "THREE.Sprite", "contents": "THREE.Sprite( ${1:material} )$0" }, - { "trigger": "THREE.Scene", "contents": "THREE.Scene()$0" }, - { "trigger": "THREE.Fog", "contents": "THREE.Fog( ${1:hex}, ${2:near}, ${3:far} )$0" }, - { "trigger": "THREE.FogExp2", "contents": "THREE.FogExp2( ${1:hex}, ${2:density} )$0" }, - { "trigger": "THREE.CanvasRenderer", "contents": "THREE.CanvasRenderer( ${1:parameters} )$0" }, - { "trigger": "THREE.WebGLRenderer", "contents": "THREE.WebGLRenderer( ${1:parameters} )$0" }, - { "trigger": "THREE.WebGLRenderTarget", "contents": "THREE.WebGLRenderTarget( ${1:width}, ${2:height}, ${3:options} )$0" }, - { "trigger": "THREE.WebGLRenderTargetCube", "contents": "THREE.WebGLRenderTargetCube( ${1:width}, ${2:height}, ${3:options} )$0" }, - { "trigger": "THREE.RenderableVertex", "contents": "THREE.RenderableVertex()$0" }, - { "trigger": "THREE.RenderableFace3", "contents": "THREE.RenderableFace3()$0" }, - { "trigger": "THREE.RenderableObject", "contents": "THREE.RenderableObject()$0" }, - { "trigger": "THREE.RenderableParticle", "contents": "THREE.RenderableParticle()$0" }, - { "trigger": "THREE.RenderableLine", "contents": "THREE.RenderableLine()$0" }, - { "trigger": "THREE.Curve", "contents": "THREE.Curve()$0" }, - { "trigger": "THREE.CurvePath", "contents": "THREE.CurvePath()$0" }, - { "trigger": "THREE.Gyroscope", "contents": "THREE.Gyroscope()$0" }, - { "trigger": "THREE.Path", "contents": "THREE.Path( ${1:points} )$0" }, - { "trigger": "THREE.Shape", "contents": "THREE.Shape()$0" }, - { "trigger": "THREE.LineCurve", "contents": "THREE.LineCurve( ${1:v1}, ${2:v2} )$0" }, - { "trigger": "THREE.QuadraticBezierCurve", "contents": "THREE.QuadraticBezierCurve( ${1:v0}, ${2:v1}, ${3:v2} )$0" }, - { "trigger": "THREE.CubicBezierCurve", "contents": "THREE.CubicBezierCurve( ${1:v0}, ${2:v1}, ${3:v2}, ${4:v3} )$0" }, - { "trigger": "THREE.ArcCurve", "contents": "THREE.ArcCurve( ${1:aX}, ${2:aY}, ${3:aRadius}, ${4:aStartAngle}, ${5:aEndAngle}, ${6:aClockwise} )$0" }, - { "trigger": "THREE.Animation", "contents": "THREE.Animation( ${1:root}, ${2:name}, ${3:interpolationType} )$0" }, - { "trigger": "THREE.CubeCamera", "contents": "THREE.CubeCamera( ${1:near}, ${2:far}, ${3:cubeResolution} )$0" }, - { "trigger": "THREE.CombinedCamera", "contents": "THREE.CombinedCamera( ${1:width}, ${2:height}, ${3:fov}, ${4:near}, ${5:far}, ${6:orthoNear}, ${7:orthoFar} )$0" }, - { "trigger": "THREE.CircleGeometry", "contents": "THREE.CircleGeometry( ${1:radius}, ${2:segments}, ${3:thetaStart}, ${4:thetaLength} )$0" }, - { "trigger": "THREE.CubeGeometry", "contents": "THREE.CubeGeometry( ${1:width}, ${2:height}, ${3:depth}, ${4:widthSegments}, ${5:heightSegments}, ${6:depthSegments} )$0" }, - { "trigger": "THREE.CylinderGeometry", "contents": "THREE.CylinderGeometry( ${1:radiusTop}, ${2:radiusBottom}, ${3:height}, ${4:radialSegments}, ${5:heightSegments}, ${6:openEnded} )$0" }, - { "trigger": "THREE.ExtrudeGeometry", "contents": "THREE.ExtrudeGeometry( ${1:shapes}, ${2:options} )$0" }, - { "trigger": "THREE.ShapeGeometry", "contents": "THREE.ShapeGeometry( ${1:shapes}, ${2:options} )$0" }, - { "trigger": "THREE.LatheGeometry", "contents": "THREE.LatheGeometry( ${1:points}, ${2:segments}, ${3:phiStart}, ${4:phiLength} )$0" }, - { "trigger": "THREE.PlaneGeometry", "contents": "THREE.PlaneGeometry( ${1:width}, ${2:height}, ${3:widthSegments}, ${4:heightSegments} )$0" }, - { "trigger": "THREE.RingGeometry", "contents": "THREE.RingGeometry( ${1:innerRadius}, ${2:outerRadius}, ${3:thetaSegments}, ${4:phiSegments}, ${5:thetaStart}, ${6:thetaLength} )$0" }, - { "trigger": "THREE.SphereGeometry", "contents": "THREE.SphereGeometry( ${1:radius}, ${2:widthSegments}, ${3:heightSegments}, ${4:phiStart}, ${5:phiLength}, ${6:thetaStart}, ${7:thetaLength} )$0" }, - { "trigger": "THREE.TextGeometry", "contents": "THREE.TextGeometry( ${1:text}, ${2:parameters} )$0" }, - { "trigger": "THREE.TorusGeometry", "contents": "THREE.TorusGeometry( ${1:radius}, ${2:tube}, ${3:radialSegments}, ${4:tubularSegments}, ${5:arc} )$0" }, - { "trigger": "THREE.TorusKnotGeometry", "contents": "THREE.TorusKnotGeometry( ${1:radius}, ${2:tube}, ${3:radialSegments}, ${4:tubularSegments}, ${5:p}, ${6:q}, ${7:heightScale} )$0" }, - { "trigger": "THREE.PolyhedronGeometry", "contents": "THREE.PolyhedronGeometry( ${1:vertices}, ${2:faces}, ${3:radius}, ${4:detail} )$0" }, - { "trigger": "THREE.IcosahedronGeometry", "contents": "THREE.IcosahedronGeometry( ${1:radius}, ${2:detail} )$0" }, - { "trigger": "THREE.OctahedronGeometry", "contents": "THREE.OctahedronGeometry( ${1:radius}, ${2:detail} )$0" }, - { "trigger": "THREE.TetrahedronGeometry", "contents": "THREE.TetrahedronGeometry( ${1:radius}, ${2:detail} )$0" }, - { "trigger": "THREE.ParametricGeometry", "contents": "THREE.ParametricGeometry( ${1:func}, ${2:slices}, ${3:stacks} )$0" }, - { "trigger": "THREE.AxisHelper", "contents": "THREE.AxisHelper( ${1:size} )$0" }, - { "trigger": "THREE.ArrowHelper", "contents": "THREE.ArrowHelper( ${1:dir}, ${2:origin}, ${3:length}, ${4:hex} )$0" }, - { "trigger": "THREE.BoxHelper", "contents": "THREE.BoxHelper( ${1:object} )$0" }, - { "trigger": "THREE.BoundingBoxHelper", "contents": "THREE.BoundingBoxHelper( ${1:object}, ${2:hex} )$0" }, - { "trigger": "THREE.CameraHelper", "contents": "THREE.CameraHelper( ${1:camera} )$0" }, - { "trigger": "THREE.DirectionalLightHelper", "contents": "THREE.DirectionalLightHelper( ${1:light}, ${2:size} )$0" }, - { "trigger": "THREE.FaceNormalsHelper", "contents": "THREE.FaceNormalsHelper( ${1:object}, ${2:size}, ${3:hex}, ${4:linewidth} )$0" }, - { "trigger": "THREE.GridHelper", "contents": "THREE.GridHelper( ${1:size}, ${2:step} )$0" }, - { "trigger": "THREE.HemisphereLightHelper", "contents": "THREE.HemisphereLightHelper( ${1:light}, ${2:sphereSize}, ${3:arrowLength}, ${4:domeSize} )$0" }, - { "trigger": "THREE.PointLightHelper", "contents": "THREE.PointLightHelper( ${1:light}, ${2:sphereSize} )$0" }, - { "trigger": "THREE.SpotLightHelper", "contents": "THREE.SpotLightHelper( ${1:light} )$0" }, - { "trigger": "THREE.VertexNormalsHelper", "contents": "THREE.VertexNormalsHelper( ${1:object}, ${2:size}, ${3:hex}, ${4:linewidth} )$0" }, - { "trigger": "THREE.VertexTangentsHelper", "contents": "THREE.VertexTangentsHelper( ${1:object}, ${2:size}, ${3:hex}, ${4:linewidth} )$0" }, - { "trigger": "THREE.WireframeHelper", "contents": "THREE.WireframeHelper( ${1:object} )$0" }, - { "trigger": "THREE.ImmediateRenderObject", "contents": "THREE.ImmediateRenderObject()$0" }, - { "trigger": "THREE.LensFlare", "contents": "THREE.LensFlare( ${1:texture}, ${2:size}, ${3:distance}, ${4:blending}, ${5:color} )$0" }, - { "trigger": "THREE.LensFlarePlugin", "contents": "THREE.LensFlarePlugin()$0" }, - { "trigger": "THREE.ShadowMapPlugin", "contents": "THREE.ShadowMapPlugin()$0" }, - { "trigger": "THREE.SpritePlugin", "contents": "THREE.SpritePlugin()$0" }, - { "trigger": "THREE.DepthPassPlugin", "contents": "THREE.DepthPassPlugin()$0" }, - "THREE" - ] -} diff --git a/utils/exporters/blender/.gitignore b/utils/exporters/blender/.gitignore index 90e54781632294..c1c6da1922d327 100644 --- a/utils/exporters/blender/.gitignore +++ b/utils/exporters/blender/.gitignore @@ -1,2 +1,3 @@ tests/review __pycache__/ +tmp/ diff --git a/utils/exporters/blender/addons/io_three/__init__.py b/utils/exporters/blender/addons/io_three/__init__.py index b334a26866595f..db277ec82b7146 100644 --- a/utils/exporters/blender/addons/io_three/__init__.py +++ b/utils/exporters/blender/addons/io_three/__init__.py @@ -18,6 +18,7 @@ import os import json +import logging import bpy from bpy_extras.io_utils import ExportHelper @@ -25,141 +26,189 @@ EnumProperty, BoolProperty, FloatProperty, - IntProperty + IntProperty, + StringProperty ) from . import constants -SETTINGS_FILE_EXPORT = 'three_settings_export.js' - +logging.basicConfig( + format='%(levelname)s:THREE:%(message)s', + level=logging.DEBUG) bl_info = { - 'name': 'Three.js Format', - 'author': 'Ed Caspersen (repsac)', - 'version': (1, 0, 0), - 'blender': (2, 7, 2), - 'location': 'File > Import-Export', - 'description': 'Export Three.js formatted JSON files.', - 'warning': '', - 'wiki_url': 'https://github.com/mrdoob/three.js/tree/'\ - 'master/utils/exporters/blender', - 'tracker_url': 'https://github.com/mrdoob/three.js/issues', + 'name': "Three.js Format", + 'author': "repsac, mrdoob, yomotsu, mpk, jpweeks, rkusa", + 'version': (1, 4, 0), + 'blender': (2, 7, 3), + 'location': "File > Export", + 'description': "Export Three.js formatted JSON files.", + 'warning': "Importer not included.", + 'wiki_url': "https://github.com/mrdoob/three.js/tree/"\ + "master/utils/exporters/blender", + 'tracker_url': "https://github.com/mrdoob/three.js/issues", 'category': 'Import-Export' } + def _geometry_types(): - types = [ - (constants.GLOBAL, constants.GLOBAL.title(), - constants.GLOBAL), - (constants.GEOMETRY, constants.GEOMETRY.title(), - constants.GEOMETRY), - (constants.BUFFER_GEOMETRY, constants.BUFFER_GEOMETRY, - constants.BUFFER_GEOMETRY), - ] + """The valid geometry types that are supported by Three.js + + :return: list of tuples + + """ + keys = (constants.GLOBAL, + constants.GEOMETRY, + constants.BUFFER_GEOMETRY) + types = [] + for key in keys: + types.append((key, key.title(), key)) return types bpy.types.Mesh.THREE_geometry_type = EnumProperty( - name='Geometry type', - description='Geometry type', + name="Geometry type", + description="Geometry type", items=_geometry_types(), default=constants.GLOBAL) -class MESH_PT_hello(bpy.types.Panel): +class ThreeMesh(bpy.types.Panel): + """Creates custom properties on a mesh node""" bl_label = 'THREE' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = 'data' - + def draw(self, context): + """ + + :param context: + + """ row = self.layout.row() if context.mesh: - row.prop(context.mesh, 'THREE_geometry_type', text='Type') + row.prop(context.mesh, + 'THREE_geometry_type', + text="Type") def _blending_types(index): - types = ( - constants.BLENDING_TYPES.NONE, - constants.BLENDING_TYPES.NORMAL, - constants.BLENDING_TYPES.ADDITIVE, - constants.BLENDING_TYPES.SUBTRACTIVE, - constants.BLENDING_TYPES.MULTIPLY, - constants.BLENDING_TYPES.CUSTOM) + """Supported blending types for Three.js + + :param index: + :type index: int + :returns: tuple if types (str, str, str) + + """ + types = (constants.BLENDING_TYPES.NONE, + constants.BLENDING_TYPES.NORMAL, + constants.BLENDING_TYPES.ADDITIVE, + constants.BLENDING_TYPES.SUBTRACTIVE, + constants.BLENDING_TYPES.MULTIPLY, + constants.BLENDING_TYPES.CUSTOM) return (types[index], types[index], types[index]) bpy.types.Material.THREE_blending_type = EnumProperty( - name='Blending type', - description='Blending type', - items=[_blending_types(x) for x in range(5)], + name="Blending type", + description="Blending type", + items=[_blending_types(x) for x in range(5)], default=constants.BLENDING_TYPES.NORMAL) bpy.types.Material.THREE_depth_write = BoolProperty(default=True) bpy.types.Material.THREE_depth_test = BoolProperty(default=True) -class MATERIAL_PT_hello(bpy.types.Panel): +class ThreeMaterial(bpy.types.Panel): + """Adds custom properties to the Materials of an object""" bl_label = 'THREE' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = 'material' - + def draw(self, context): + """ + + :param context: + + """ layout = self.layout mat = context.material - + if mat is not None: row = layout.row() - row.label(text='Selected material: %s' % mat.name ) + row.label(text="Selected material: %s" % mat.name) row = layout.row() - row.prop(mat, 'THREE_blending_type', - text='Blending type' ) + row.prop(mat, 'THREE_blending_type', + text="Blending type") row = layout.row() - row.prop(mat, 'THREE_depth_write', - text='Enable depth writing' ) + row.prop(mat, 'THREE_depth_write', + text="Enable depth writing") row = layout.row() - row.prop(mat, 'THREE_depth_test', - text='Enable depth testing' ) + row.prop(mat, 'THREE_depth_test', + text="Enable depth testing") def _mag_filters(index): + """Three.js mag filters + + :param index: + :type index: int + :returns: tuple with the filter values + + """ types = (constants.LINEAR_FILTERS.LINEAR, - constants.NEAREST_FILTERS.NEAREST) + constants.NEAREST_FILTERS.NEAREST) return (types[index], types[index], types[index]) bpy.types.Texture.THREE_mag_filter = EnumProperty( - name='Mag Filter', - items = [_mag_filters(x) for x in range(2)], + name="Mag Filter", + items=[_mag_filters(x) for x in range(2)], default=constants.LINEAR_FILTERS.LINEAR) def _min_filters(index): + """Three.js min filters + + :param index: + :type index: int + :returns: tuple with the filter values + + """ types = (constants.LINEAR_FILTERS.LINEAR, - constants.LINEAR_FILTERS.MIP_MAP_NEAREST, - constants.LINEAR_FILTERS.MIP_MAP_LINEAR, - constants.NEAREST_FILTERS.NEAREST, - constants.NEAREST_FILTERS.MIP_MAP_NEAREST, - constants.NEAREST_FILTERS.MIP_MAP_LINEAR) + constants.LINEAR_FILTERS.MIP_MAP_NEAREST, + constants.LINEAR_FILTERS.MIP_MAP_LINEAR, + constants.NEAREST_FILTERS.NEAREST, + constants.NEAREST_FILTERS.MIP_MAP_NEAREST, + constants.NEAREST_FILTERS.MIP_MAP_LINEAR) return (types[index], types[index], types[index]) bpy.types.Texture.THREE_min_filter = EnumProperty( - name='Min Filter', - items = [_min_filters(x) for x in range(6)], + name="Min Filter", + items=[_min_filters(x) for x in range(6)], default=constants.LINEAR_FILTERS.MIP_MAP_LINEAR) def _mapping(index): + """Three.js texture mappings types + + :param index: + :type index: int + :returns: tuple with the mapping values + + """ types = (constants.MAPPING_TYPES.UV, - constants.MAPPING_TYPES.CUBE_REFLECTION, - constants.MAPPING_TYPES.CUBE_REFRACTION, - constants.MAPPING_TYPES.SPHERICAL_REFLECTION) + constants.MAPPING_TYPES.CUBE_REFLECTION, + constants.MAPPING_TYPES.CUBE_REFRACTION, + constants.MAPPING_TYPES.SPHERICAL_REFLECTION) return (types[index], types[index], types[index]) bpy.types.Texture.THREE_mapping = EnumProperty( - name='Mapping', - items = [_mapping(x) for x in range(4)], + name="Mapping", + items=[_mapping(x) for x in range(4)], default=constants.MAPPING_TYPES.UV) -class TEXTURE_PT_hello(bpy.types.Panel): +class ThreeTexture(bpy.types.Panel): + """Adds custom properties to a texture""" bl_label = 'THREE' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -167,108 +216,85 @@ class TEXTURE_PT_hello(bpy.types.Panel): #@TODO: possible to make cycles compatible? def draw(self, context): + """ + + :param context: + + """ layout = self.layout tex = context.texture if tex is not None: row = layout.row() - row.prop(tex, 'THREE_mapping', text='Mapping') + row.prop(tex, 'THREE_mapping', text="Mapping") row = layout.row() - row.prop(tex, 'THREE_mag_filter', text='Mag Filter') + row.prop(tex, 'THREE_mag_filter', text="Mag Filter") row = layout.row() - row.prop(tex, 'THREE_min_filter', text='Min Filter') + row.prop(tex, 'THREE_min_filter', text="Min Filter") bpy.types.Object.THREE_export = bpy.props.BoolProperty(default=True) -class OBJECT_PT_hello(bpy.types.Panel): +class ThreeObject(bpy.types.Panel): + """Adds custom properties to an object""" bl_label = 'THREE' bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = 'object' def draw(self, context): + """ + + :param context: + + """ layout = self.layout obj = context.object row = layout.row() row.prop(obj, 'THREE_export', text='Export') -def get_settings_fullpath(): - return os.path.join(bpy.app.tempdir, SETTINGS_FILE_EXPORT) - - -def save_settings_export(properties): +class ThreeExportSettings(bpy.types.Operator): + """Save the current export settings (gets saved in .blend)""" + bl_label = "Save Settings" + bl_idname = "scene.three_export_settings_set" - settings = { - constants.VERTICES: properties.option_vertices, - constants.FACES: properties.option_faces, - constants.NORMALS: properties.option_normals, - constants.SKINNING: properties.option_skinning, - constants.BONES: properties.option_bones, - constants.GEOMETRY_TYPE: properties.option_geometry_type, - - constants.MATERIALS: properties.option_materials, - constants.UVS: properties.option_uv_coords, - constants.FACE_MATERIALS: properties.option_face_materials, - constants.MAPS: properties.option_maps, - constants.COLORS: properties.option_colors, - constants.MIX_COLORS: properties.option_mix_colors, - - constants.SCALE: properties.option_scale, - constants.ENABLE_PRECISION: properties.option_round_off, - constants.PRECISION: properties.option_round_value, - constants.LOGGING: properties.option_logging, - constants.COMPRESSION: properties.option_compression, - constants.COPY_TEXTURES: properties.option_copy_textures, - - constants.SCENE: properties.option_export_scene, - constants.EMBED_GEOMETRY: properties.option_embed_geometry, - constants.EMBED_ANIMATION: properties.option_embed_animation, - constants.LIGHTS: properties.option_lights, - constants.CAMERAS: properties.option_cameras, - - constants.MORPH_TARGETS: properties.option_animation_morph, - constants.ANIMATION: properties.option_animation_skeletal, - constants.FRAME_STEP: properties.option_frame_step, - constants.INFLUENCES_PER_VERTEX: properties.option_influences - } + def execute(self, context): + cycles = context.scene.cycles + cycles.use_samples_final = True - fname = get_settings_fullpath() - with open(fname, 'w') as stream: - json.dump(settings, stream) + context.scene[constants.EXPORT_SETTINGS_KEY] = set_settings(context.active_operator.properties) - return settings + self.report({"INFO"}, "Three Export Settings Saved") + return {"FINISHED"} -def restore_settings_export(properties): +def restore_export_settings(properties, settings): + """Restore the settings - settings = {} + :param properties: - fname = get_settings_fullpath() - if os.path.exists(fname) and os.access(fname, os.R_OK): - f = open(fname, 'r') - settings = json.load(f) + """ ## Geometry { properties.option_vertices = settings.get( - constants.VERTICES, + constants.VERTICES, constants.EXPORT_OPTIONS[constants.VERTICES]) properties.option_faces = settings.get( - constants.FACES, + constants.FACES, constants.EXPORT_OPTIONS[constants.FACES]) properties.option_normals = settings.get( - constants.NORMALS, + constants.NORMALS, constants.EXPORT_OPTIONS[constants.NORMALS]) properties.option_skinning = settings.get( - constants.SKINNING, + constants.SKINNING, constants.EXPORT_OPTIONS[constants.SKINNING]) properties.option_bones = settings.get( - constants.BONES, + constants.BONES, constants.EXPORT_OPTIONS[constants.BONES]) properties.option_influences = settings.get( @@ -282,185 +308,272 @@ def restore_settings_export(properties): ## Materials { properties.option_materials = settings.get( - constants.MATERIALS, + constants.MATERIALS, constants.EXPORT_OPTIONS[constants.MATERIALS]) properties.option_uv_coords = settings.get( - constants.UVS, + constants.UVS, constants.EXPORT_OPTIONS[constants.UVS]) properties.option_face_materials = settings.get( - constants.FACE_MATERIALS, + constants.FACE_MATERIALS, constants.EXPORT_OPTIONS[constants.FACE_MATERIALS]) properties.option_maps = settings.get( - constants.MAPS, + constants.MAPS, constants.EXPORT_OPTIONS[constants.MAPS]) properties.option_colors = settings.get( - constants.COLORS, + constants.COLORS, constants.EXPORT_OPTIONS[constants.COLORS]) properties.option_mix_colors = settings.get( - constants.MIX_COLORS, + constants.MIX_COLORS, constants.EXPORT_OPTIONS[constants.MIX_COLORS]) ## } ## Settings { properties.option_scale = settings.get( - constants.SCALE, + constants.SCALE, constants.EXPORT_OPTIONS[constants.SCALE]) properties.option_round_off = settings.get( - constants.ENABLE_PRECISION, + constants.ENABLE_PRECISION, constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION]) properties.option_round_value = settings.get( - constants.PRECISION, + constants.PRECISION, constants.EXPORT_OPTIONS[constants.PRECISION]) properties.option_logging = settings.get( - constants.LOGGING, + constants.LOGGING, constants.EXPORT_OPTIONS[constants.LOGGING]) properties.option_compression = settings.get( - constants.COMPRESSION, + constants.COMPRESSION, constants.NONE) + properties.option_indent = settings.get( + constants.INDENT, + constants.EXPORT_OPTIONS[constants.INDENT]) + properties.option_copy_textures = settings.get( - constants.COPY_TEXTURES, + constants.COPY_TEXTURES, constants.EXPORT_OPTIONS[constants.COPY_TEXTURES]) + properties.option_texture_folder = settings.get( + constants.TEXTURE_FOLDER, + constants.EXPORT_OPTIONS[constants.TEXTURE_FOLDER]) + properties.option_embed_animation = settings.get( - constants.EMBED_ANIMATION, + constants.EMBED_ANIMATION, constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION]) ## } ## Scene { properties.option_export_scene = settings.get( - constants.SCENE, + constants.SCENE, constants.EXPORT_OPTIONS[constants.SCENE]) - properties.option_embed_geometry = settings.get( - constants.EMBED_GEOMETRY, - constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY]) + #properties.option_embed_geometry = settings.get( + # constants.EMBED_GEOMETRY, + # constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY]) properties.option_lights = settings.get( - constants.LIGHTS, + constants.LIGHTS, constants.EXPORT_OPTIONS[constants.LIGHTS]) properties.option_cameras = settings.get( - constants.CAMERAS, + constants.CAMERAS, constants.EXPORT_OPTIONS[constants.CAMERAS]) + + properties.option_hierarchy = settings.get( + constants.HIERARCHY, + constants.EXPORT_OPTIONS[constants.HIERARCHY]) ## } ## Animation { properties.option_animation_morph = settings.get( - constants.MORPH_TARGETS, + constants.MORPH_TARGETS, constants.EXPORT_OPTIONS[constants.MORPH_TARGETS]) properties.option_animation_skeletal = settings.get( - constants.ANIMATION, + constants.ANIMATION, constants.EXPORT_OPTIONS[constants.ANIMATION]) properties.option_frame_step = settings.get( - constants.FRAME_STEP, + constants.FRAME_STEP, constants.EXPORT_OPTIONS[constants.FRAME_STEP]) + + properties.option_frame_index_as_time = settings.get( + constants.FRAME_INDEX_AS_TIME, + constants.EXPORT_OPTIONS[constants.FRAME_INDEX_AS_TIME]) ## } +def set_settings(properties): + """Set the export settings to the correct keys. + + :param properties: + :returns: settings + :rtype: dict + + """ + settings = { + constants.VERTICES: properties.option_vertices, + constants.FACES: properties.option_faces, + constants.NORMALS: properties.option_normals, + constants.SKINNING: properties.option_skinning, + constants.BONES: properties.option_bones, + constants.GEOMETRY_TYPE: properties.option_geometry_type, + + constants.MATERIALS: properties.option_materials, + constants.UVS: properties.option_uv_coords, + constants.FACE_MATERIALS: properties.option_face_materials, + constants.MAPS: properties.option_maps, + constants.COLORS: properties.option_colors, + constants.MIX_COLORS: properties.option_mix_colors, + + constants.SCALE: properties.option_scale, + constants.ENABLE_PRECISION: properties.option_round_off, + constants.PRECISION: properties.option_round_value, + constants.LOGGING: properties.option_logging, + constants.COMPRESSION: properties.option_compression, + constants.INDENT: properties.option_indent, + constants.COPY_TEXTURES: properties.option_copy_textures, + constants.TEXTURE_FOLDER: properties.option_texture_folder, + + constants.SCENE: properties.option_export_scene, + #constants.EMBED_GEOMETRY: properties.option_embed_geometry, + constants.EMBED_ANIMATION: properties.option_embed_animation, + constants.LIGHTS: properties.option_lights, + constants.CAMERAS: properties.option_cameras, + constants.HIERARCHY: properties.option_hierarchy, + + constants.MORPH_TARGETS: properties.option_animation_morph, + constants.ANIMATION: properties.option_animation_skeletal, + constants.FRAME_STEP: properties.option_frame_step, + constants.FRAME_INDEX_AS_TIME: properties.option_frame_index_as_time, + constants.INFLUENCES_PER_VERTEX: properties.option_influences + } + + return settings + + def compression_types(): + """Supported compression formats + + :rtype: tuple + + """ types = [(constants.NONE, constants.NONE, constants.NONE)] try: import msgpack - types.append((constants.MSGPACK, constants.MSGPACK, - constants.MSGPACK)) + types.append((constants.MSGPACK, constants.MSGPACK, + constants.MSGPACK)) except ImportError: pass return types + +def animation_options(): + """The supported skeletal animation types + + :returns: list of tuples + + """ + anim = [ + (constants.OFF, constants.OFF.title(), constants.OFF), + (constants.POSE, constants.POSE.title(), constants.POSE), + (constants.REST, constants.REST.title(), constants.REST) + ] + + return anim + class ExportThree(bpy.types.Operator, ExportHelper): + """Class that handles the export properties""" - bl_idname='export.three' + bl_idname = 'export.three' bl_label = 'Export THREE' + bl_options = {'PRESET'} filename_ext = constants.EXTENSION option_vertices = BoolProperty( - name='Vertices', - description='Export vertices', + name="Vertices", + description="Export vertices", default=constants.EXPORT_OPTIONS[constants.VERTICES]) option_faces = BoolProperty( - name='Faces', - description='Export faces', + name="Faces", + description="Export faces", default=constants.EXPORT_OPTIONS[constants.FACES]) option_normals = BoolProperty( - name='Normals', - description='Export normals', + name="Normals", + description="Export normals", default=constants.EXPORT_OPTIONS[constants.NORMALS]) option_colors = BoolProperty( - name='Colors', - description='Export vertex colors', + name="Vertex Colors", + description="Export vertex colors", default=constants.EXPORT_OPTIONS[constants.COLORS]) option_mix_colors = BoolProperty( - name='Mix Colors', - description='Mix material and vertex colors', + name="Mix Colors", + description="Mix material and vertex colors", default=constants.EXPORT_OPTIONS[constants.MIX_COLORS]) option_uv_coords = BoolProperty( - name='UVs', - description='Export texture coordinates', + name="UVs", + description="Export texture coordinates", default=constants.EXPORT_OPTIONS[constants.UVS]) option_materials = BoolProperty( - name='Materials', - description='Export materials', + name="Materials", + description="Export materials", default=constants.EXPORT_OPTIONS[constants.MATERIALS]) option_face_materials = BoolProperty( - name='Face Materials', - description='Face mapping materials', + name="Face Materials", + description="Face mapping materials", default=constants.EXPORT_OPTIONS[constants.FACE_MATERIALS]) option_maps = BoolProperty( - name='Textures', - description='Include texture maps', + name="Textures", + description="Include texture maps", default=constants.EXPORT_OPTIONS[constants.MAPS]) option_skinning = BoolProperty( - name='Skinning', - description='Export skin data', + name="Skinning", + description="Export skin data", default=constants.EXPORT_OPTIONS[constants.SKINNING]) option_bones = BoolProperty( - name='Bones', - description='Export bones', + name="Bones", + description="Export bones", default=constants.EXPORT_OPTIONS[constants.BONES]) option_scale = FloatProperty( - name='Scale', - description='Scale vertices', - min=0.01, - max=1000.0, - soft_min=0.01, - soft_max=1000.0, + name="Scale", + description="Scale vertices", + min=0.01, + max=1000.0, + soft_min=0.01, + soft_max=1000.0, default=constants.EXPORT_OPTIONS[constants.SCALE]) option_round_off = BoolProperty( - name='Enable Precision', - description='Round off floating point values', + name="Enable Precision", + description="Round off floating point values", default=constants.EXPORT_OPTIONS[constants.ENABLE_PRECISION]) option_round_value = IntProperty( - name='Precision', + name="Precision", min=0, max=16, - description='Floating point precision', + description="Floating point precision", default=constants.EXPORT_OPTIONS[constants.PRECISION]) logging_types = [ @@ -471,96 +584,140 @@ class ExportThree(bpy.types.Operator, ExportHelper): (constants.CRITICAL, constants.CRITICAL, constants.CRITICAL)] option_logging = EnumProperty( - name='Logging', - description = 'Logging verbosity level', - items=logging_types, + name="", + description="Logging verbosity level", + items=logging_types, default=constants.DEBUG) option_geometry_type = EnumProperty( - name='Type', - description='Geometry type', + name="Type", + description="Geometry type", items=_geometry_types()[1:], default=constants.GEOMETRY) option_export_scene = BoolProperty( - name='Scene', - description='Export scene', + name="Scene", + description="Export scene", default=constants.EXPORT_OPTIONS[constants.SCENE]) - option_embed_geometry = BoolProperty( - name='Embed geometry', - description='Embed geometry', - default=constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY]) + #@TODO: removing this option since the ObjectLoader doesn't have + # support for handling external geometry data + #option_embed_geometry = BoolProperty( + # name="Embed geometry", + # description="Embed geometry", + # default=constants.EXPORT_OPTIONS[constants.EMBED_GEOMETRY]) option_embed_animation = BoolProperty( - name='Embed animation', - description='Embed animation data with the geometry data', + name="Embed animation", + description="Embed animation data with the geometry data", default=constants.EXPORT_OPTIONS[constants.EMBED_ANIMATION]) option_copy_textures = BoolProperty( - name='Copy textures', - description='Copy textures', + name="Copy textures", + description="Copy textures", default=constants.EXPORT_OPTIONS[constants.COPY_TEXTURES]) + option_texture_folder = StringProperty( + name="Texture folder", + description="add this folder to textures path", + default=constants.EXPORT_OPTIONS[constants.TEXTURE_FOLDER]) + option_lights = BoolProperty( - name='Lights', - description='Export default scene lights', + name="Lights", + description="Export default scene lights", default=False) option_cameras = BoolProperty( - name='Cameras', - description='Export default scene cameras', + name="Cameras", + description="Export default scene cameras", + default=False) + + option_hierarchy = BoolProperty( + name="Hierarchy", + description="Export object hierarchy", default=False) option_animation_morph = BoolProperty( - name='Morph animation', - description='Export animation (morphs)', + name="Morph animation", + description="Export animation (morphs)", default=constants.EXPORT_OPTIONS[constants.MORPH_TARGETS]) - option_animation_skeletal = BoolProperty( - name='Skeletal animation', - description='Export animation (skeletal)', - default=constants.EXPORT_OPTIONS[constants.ANIMATION]) + option_animation_skeletal = EnumProperty( + name="", + description="Export animation (skeletal)", + items=animation_options(), + default=constants.OFF) + + option_frame_index_as_time = BoolProperty( + name="Frame index as time", + description="Use (original) frame index as frame time", + default=constants.EXPORT_OPTIONS[constants.FRAME_INDEX_AS_TIME]) option_frame_step = IntProperty( - name='Frame step', - description='Animation frame step', - min=1, - max=1000, - soft_min=1, - soft_max=1000, + name="Frame step", + description="Animation frame step", + min=1, + max=1000, + soft_min=1, + soft_max=1000, default=1) - + + option_indent = BoolProperty( + name="Indent JSON", + description="Disable this to reduce the file size", + default=constants.EXPORT_OPTIONS[constants.INDENT]) + option_compression = EnumProperty( - name='Compression', - description = 'Compression options', - items=compression_types(), + name="", + description="Compression options", + items=compression_types(), default=constants.NONE) option_influences = IntProperty( - name='Influences', - description='Maximum number of bone influences', + name="Influences", + description="Maximum number of bone influences", min=1, max=4, default=2) def invoke(self, context, event): - restore_settings_export(self.properties) + settings = context.scene.get(constants.EXPORT_SETTINGS_KEY) + if settings: + try: + restore_export_settings(self.properties, settings) + except AttributeError as e: + logging.error("Loading export settings failed:") + logging.exception(e) + logging.debug("Removed corrupted settings") + + del context.scene[constants.EXPORT_SETTINGS_KEY] + return ExportHelper.invoke(self, context, event) @classmethod def poll(cls, context): + """ + + :param context: + + """ return context.active_object is not None def execute(self, context): + """ + + :param context: + + """ if not self.properties.filepath: - raise Exception('filename not set') + raise Exception("filename not set") - settings = save_settings_export(self.properties) + settings = set_settings(self.properties) + settings['addon_version'] = bl_info['version'] filepath = self.filepath if settings[constants.COMPRESSION] == constants.MSGPACK: - filepath = '%s%s' % (filepath[:-4], constants.PACK) + filepath = "%s%s" % (filepath[:-4], constants.PACK) from io_three import exporter if settings[constants.SCENE]: @@ -571,11 +728,16 @@ def execute(self, context): return {'FINISHED'} def draw(self, context): + """ + + :param context: + + """ layout = self.layout ## Geometry { row = layout.row() - row.label(text='Geometry:') + row.label(text="GEOMETRY:") row = layout.row() row.prop(self.properties, 'option_vertices') @@ -583,6 +745,7 @@ def draw(self, context): row = layout.row() row.prop(self.properties, 'option_normals') + row.prop(self.properties, 'option_uv_coords') row = layout.row() row.prop(self.properties, 'option_bones') @@ -591,102 +754,151 @@ def draw(self, context): row = layout.row() row.prop(self.properties, 'option_geometry_type') - row = layout.row() - row.prop(self.properties, 'option_influences') ## } layout.separator() ## Materials { row = layout.row() - row.label(text='Materials:') - - row = layout.row() - row.prop(self.properties, 'option_materials') - row.prop(self.properties, 'option_uv_coords') + row.label(text="- Shading:") row = layout.row() row.prop(self.properties, 'option_face_materials') - row.prop(self.properties, 'option_maps') row = layout.row() row.prop(self.properties, 'option_colors') + + row = layout.row() row.prop(self.properties, 'option_mix_colors') ## } - + layout.separator() - ## Settings { + ## Animation { row = layout.row() - row.label(text='Settings:') + row.label(text="- Animation:") row = layout.row() - row.prop(self.properties, 'option_scale') - + row.prop(self.properties, 'option_animation_morph') + row = layout.row() - row.prop(self.properties, 'option_round_off') - row.prop(self.properties, 'option_round_value') + row.label(text="Skeletal animations:") row = layout.row() - row.prop(self.properties, 'option_logging') + row.prop(self.properties, 'option_animation_skeletal') + layout.row() row = layout.row() - row.prop(self.properties, 'option_compression') + row.prop(self.properties, 'option_influences') row = layout.row() - row.prop(self.properties, 'option_copy_textures') + row.prop(self.properties, 'option_frame_step') + + row = layout.row() + row.prop(self.properties, 'option_frame_index_as_time') row = layout.row() row.prop(self.properties, 'option_embed_animation') + ## } layout.separator() ## Scene { row = layout.row() - row.label(text='Scene:') + row.label(text="SCENE:") row = layout.row() row.prop(self.properties, 'option_export_scene') + row.prop(self.properties, 'option_materials') - row = layout.row() - row.prop(self.properties, 'option_embed_geometry') + #row = layout.row() + #row.prop(self.properties, 'option_embed_geometry') row = layout.row() row.prop(self.properties, 'option_lights') row.prop(self.properties, 'option_cameras') ## } + row = layout.row() + row.prop(self.properties, 'option_hierarchy') + layout.separator() - ## Animation { + ## Settings { row = layout.row() - row.label(text='Animation:') + row.label(text="SETTINGS:") row = layout.row() - row.prop(self.properties, 'option_animation_morph') + row.prop(self.properties, 'option_maps') + row = layout.row() - row.prop(self.properties, 'option_animation_skeletal') + row.prop(self.properties, 'option_copy_textures') + row = layout.row() - row.prop(self.properties, 'option_frame_step') + row.prop(self.properties, 'option_texture_folder') + + row = layout.row() + row.prop(self.properties, 'option_scale') + + layout.row() + row = layout.row() + row.prop(self.properties, 'option_round_off') + row = layout.row() + row.prop(self.properties, 'option_round_value') + + layout.row() + row = layout.row() + row.label(text="Logging verbosity:") + + row = layout.row() + row.prop(self.properties, 'option_logging') + + row = layout.row() + row.label(text="File compression format:") + + row = layout.row() + row.prop(self.properties, 'option_compression') + + row = layout.row() + row.prop(self.properties, 'option_indent') ## } + ## Operators { + has_settings = context.scene.get(constants.EXPORT_SETTINGS_KEY, False) + row = layout.row() + row.operator( + ThreeExportSettings.bl_idname, + ThreeExportSettings.bl_label, + icon="%s" % "PINNED" if has_settings else "UNPINNED") + ## } + + + def menu_func_export(self, context): + """ + + :param self: + :param context: + + """ default_path = bpy.data.filepath.replace('.blend', constants.EXTENSION) - text = 'Three (%s)' % constants.EXTENSION + text = "Three.js (%s)" % constants.EXTENSION operator = self.layout.operator(ExportThree.bl_idname, text=text) operator.filepath = default_path def register(): + """Registers the addon (Blender boilerplate)""" bpy.utils.register_module(__name__) bpy.types.INFO_MT_file_export.append(menu_func_export) def unregister(): + """Unregisters the addon (Blender boilerplate)""" bpy.utils.unregister_module(__name__) bpy.types.INFO_MT_file_export.remove(menu_func_export) if __name__ == '__main__': - register() + register() diff --git a/utils/exporters/blender/addons/io_three/constants.py b/utils/exporters/blender/addons/io_three/constants.py index 18b514d1ed8abb..9b55916c9fff06 100644 --- a/utils/exporters/blender/addons/io_three/constants.py +++ b/utils/exporters/blender/addons/io_three/constants.py @@ -34,6 +34,7 @@ JSON = 'json' EXTENSION = '.%s' % JSON +INDENT = 'indent' MATERIALS = 'materials' @@ -49,21 +50,27 @@ COMPRESSION = 'compression' MAPS = 'maps' FRAME_STEP = 'frameStep' -ANIMATION = 'animation' +FRAME_INDEX_AS_TIME = 'frameIndexAsTime' +ANIMATION = 'animations' MORPH_TARGETS = 'morphTargets' +POSE = 'pose' +REST = 'rest' SKIN_INDICES = 'skinIndices' SKIN_WEIGHTS = 'skinWeights' LOGGING = 'logging' CAMERAS = 'cameras' LIGHTS = 'lights' +HIERARCHY = 'hierarchy' FACE_MATERIALS = 'faceMaterials' SKINNING = 'skinning' COPY_TEXTURES = 'copyTextures' +TEXTURE_FOLDER = 'textureFolder' ENABLE_PRECISION = 'enablePrecision' PRECISION = 'precision' DEFAULT_PRECISION = 6 EMBED_GEOMETRY = 'embedGeometry' EMBED_ANIMATION = 'embedAnimation' +OFF = 'off' GLOBAL = 'global' BUFFER_GEOMETRY = 'BufferGeometry' @@ -86,31 +93,35 @@ EXPORT_OPTIONS = { FACES: True, VERTICES: True, - NORMALS: False, - UVS: False, + NORMALS: True, + UVS: True, COLORS: False, MATERIALS: False, FACE_MATERIALS: False, SCALE: 1, FRAME_STEP: 1, - SCENE: True, + FRAME_INDEX_AS_TIME: False, + SCENE: False, MIX_COLORS: False, COMPRESSION: None, MAPS: False, - ANIMATION: False, + ANIMATION: OFF, BONES: False, SKINNING: False, MORPH_TARGETS: False, CAMERAS: False, LIGHTS: False, + HIERARCHY: False, COPY_TEXTURES: True, + TEXTURE_FOLDER: '', LOGGING: DEBUG, - ENABLE_PRECISION: False, + ENABLE_PRECISION: True, PRECISION: DEFAULT_PRECISION, EMBED_GEOMETRY: True, EMBED_ANIMATION: True, GEOMETRY_TYPE: GEOMETRY, - INFLUENCES_PER_VERTEX: 2 + INFLUENCES_PER_VERTEX: 2, + INDENT: True } @@ -151,6 +162,7 @@ SPOT_LIGHT = 'SpotLight' HEMISPHERE_LIGHT = 'HemisphereLight' MESH = 'Mesh' +EMPTY = 'Empty' SPRITE = 'Sprite' DEFAULT_METADATA = { @@ -164,7 +176,7 @@ MATRIX = 'matrix' POSITION = 'position' QUATERNION = 'quaternion' -ROTATION ='rotation' +ROTATION = 'rotation' SCALE = 'scale' UV = 'uv' @@ -210,10 +222,15 @@ NAME = 'name' PARENT = 'parent' - -#@TODO move to api.constants? +LENGTH = 'length' +FPS = 'fps' +HIERARCHY = 'hierarchy' POS = 'pos' ROTQ = 'rotq' +ROT = 'rot' +SCL = 'scl' +TIME = 'time' +KEYS = 'keys' AMBIENT = 'ambient' COLOR = 'color' @@ -307,7 +324,9 @@ NORMAL_BLENDING = 'NormalBlending' -DBG_COLORS = (0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, 0xeeee00, 0x00eeee, 0xee00ee) +DBG_COLORS = (0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, + 0xeeee00, 0x00eeee, 0xee00ee) DOUBLE_SIDED = 'doubleSided' +EXPORT_SETTINGS_KEY = 'threeExportSettings' diff --git a/utils/exporters/blender/addons/io_three/dialogs.py b/utils/exporters/blender/addons/io_three/dialogs.py new file mode 100644 index 00000000000000..01baf18eeb2f29 --- /dev/null +++ b/utils/exporters/blender/addons/io_three/dialogs.py @@ -0,0 +1,112 @@ +from bpy import context + +CONTEXT = { + 0: { + 'title': "Error Message", + 'icon': 'CANCEL' + }, + 1: { + 'title': "Warning Message", + 'icon': 'ERROR' # I prefer this icon for warnings + }, + 2: { + 'title': "Message", + 'icon': 'NONE' + }, + 3: { + 'title': "Question", + 'icon': 'QUESTION' + } +} + + +def error(message, title="", wrap=40): + """Creates an error dialog. + + :param message: text of the message body + :param title: text to append to the title + (Default value = "") + :param wrap: line width (Default value = 40) + + """ + _draw(message, title, wrap, 0) + + +def warning(message, title="", wrap=40): + """Creates an error dialog. + + :param message: text of the message body + :param title: text to append to the title + (Default value = "") + :param wrap: line width (Default value = 40) + + """ + _draw(message, title, wrap, 1) + + + +def info(message, title="", wrap=40): + """Creates an error dialog. + + :param message: text of the message body + :param title: text to append to the title + (Default value = "") + :param wrap: line width (Default value = 40) + + """ + _draw(message, title, wrap, 2) + + + +def question(message, title="", wrap=40): + """Creates an error dialog. + + :param message: text of the message body + :param title: text to append to the title + (Default value = "") + :param wrap: line width (Default value = 40) + + """ + _draw(message, title, wrap, 3) + + + +# Great idea borrowed from +# http://community.cgcookie.com/t/code-snippet-easy-error-messages/203 +def _draw(message, title, wrap, key): + """ + + :type message: str + :type title: str + :type wrap: int + :type key: int + + """ + lines = [] + if wrap > 0: + while len(message) > wrap: + i = message.rfind(' ', 0, wrap) + if i == -1: + lines += [message[:wrap]] + message = message[wrap:] + else: + lines += [message[:i]] + message = message[i+1:] + if message: + lines += [message] + + def draw(self, *args): + """ + + :param self: + :param *args: + + """ + for line in lines: + self.layout.label(line) + + title = "%s: %s" % (title, CONTEXT[key]['title']) + icon = CONTEXT[key]['icon'] + + context.window_manager.popup_menu( + draw, title=title.strip(), icon=icon) diff --git a/utils/exporters/blender/addons/io_three/exporter/__init__.py b/utils/exporters/blender/addons/io_three/exporter/__init__.py index 4acb0d7c1ae474..90d6f871aad052 100644 --- a/utils/exporters/blender/addons/io_three/exporter/__init__.py +++ b/utils/exporters/blender/addons/io_three/exporter/__init__.py @@ -1,7 +1,7 @@ import os import sys import traceback -from .. import constants, logger, exceptions +from .. import constants, logger, exceptions, dialogs from . import scene, geometry, api, base_classes @@ -9,7 +9,10 @@ def _error_handler(func): def inner(filepath, options, *args, **kwargs): level = options.get(constants.LOGGING, constants.DEBUG) + version = options.get('addon_version') logger.init('io_three.export.log', level=level) + if version is not None: + logger.debug("Addon Version %s", version) api.init() try: @@ -55,16 +58,26 @@ def export_scene(filepath, options): @_error_handler def export_geometry(filepath, options, node=None): + msg = "" + exception = None if node is None: node = api.active_object() if node is None: - msg = 'Nothing selected' + msg = "Nothing selected" logger.error(msg) - raise exceptions.SelectionError(msg) + exception = exceptions.SelectionError if node.type != 'MESH': - msg = 'Not a valid mesh object' - raise exceptions.GeometryError(msg) + msg = "%s is not a valid mesh object" % node.name + logger.error(msg) + exception = exceptions.GeometryError + if exception is not None: + if api.batch_mode(): + raise exception(msg) + else: + dialogs.error(msg) + return + mesh = api.object.mesh(node, options) parent = base_classes.BaseScene(filepath, options) geo = geometry.Geometry(mesh, parent) diff --git a/utils/exporters/blender/addons/io_three/exporter/_json.py b/utils/exporters/blender/addons/io_three/exporter/_json.py index 82362635fd8743..50031c323d07a8 100644 --- a/utils/exporters/blender/addons/io_three/exporter/_json.py +++ b/utils/exporters/blender/addons/io_three/exporter/_json.py @@ -5,18 +5,10 @@ ## THREE override function def _json_floatstr(o): - s = str(o) - - if ROUND is None: - return s - - if '.' in s and len(s[s.index('.'):]) > ROUND - 1: - s = '%.{0}f'.format(ROUND) % o - while '.' in s and s[-1] == '0': - s = s[:-1] # this actually removes the last '0' from the string - if s[-1] == '.': # added this test to avoid leaving '0.' instead of '0.0', - s += '0' # which would throw an error while loading the file - return s + if ROUND is not None: + o = round(o, ROUND) + + return '%g' % o def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, diff --git a/utils/exporters/blender/addons/io_three/exporter/api/__init__.py b/utils/exporters/blender/addons/io_three/exporter/api/__init__.py index b4107275037094..c455561b1c8ab1 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/__init__.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/__init__.py @@ -1,20 +1,55 @@ import os import bpy -from . import object, mesh, material, camera, light +from . import object as object_, mesh, material, camera, light from .. import logger def active_object(): + """ + + :return: The actively selected object + + """ return bpy.context.scene.objects.active +def batch_mode(): + """ + + :return: Whether or not the session is interactive + :rtype: bool + + """ + return bpy.context.area is None + + +def data(node): + """ + + :param node: name of an object node + :returns: the data block of the node + + """ + try: + return bpy.data.objects[node].data + except KeyError: + pass + def init(): - logger.debug('Initializing API') - object._MESH_MAP.clear() + """Initializing the api module. Required first step before + initializing the actual export process. + """ + logger.debug("Initializing API") + object_.clear_mesh_map() def selected_objects(valid_types=None): - logger.debug('api.selected_objects(%s)', valid_types) + """Selected objects. + + :param valid_types: Filter for valid types (Default value = None) + + """ + logger.debug("api.selected_objects(%s)", valid_types) for node in bpy.context.selected_objects: if valid_types is None: yield node.name @@ -23,9 +58,20 @@ def selected_objects(valid_types=None): def set_active_object(obj): + """Set the object as active in the scene + + :param obj: + + """ + logger.debug("api.set_active_object(%s)", obj) bpy.context.scene.objects.active = obj def scene_name(): + """ + + :return: name of the current scene + + """ return os.path.basename(bpy.data.filepath) diff --git a/utils/exporters/blender/addons/io_three/exporter/api/animation.py b/utils/exporters/blender/addons/io_three/exporter/api/animation.py new file mode 100644 index 00000000000000..c8909051c189ee --- /dev/null +++ b/utils/exporters/blender/addons/io_three/exporter/api/animation.py @@ -0,0 +1,577 @@ +""" +Module for handling the parsing of skeletal animation data. +""" + +import math +import mathutils +from bpy import data, context +from .. import constants, logger + + +def pose_animation(armature, options): + """Query armature animation using pose bones + + :param armature: + :param options: + :returns: list dictionaries containing animationdata + :rtype: [{}, {}, ...] + + """ + logger.debug("animation.pose_animation(%s)", armature) + func = _parse_pose_action + return _parse_action(func, armature, options) + + +def rest_animation(armature, options): + """Query armature animation (REST position) + + :param armature: + :param options: + :returns: list dictionaries containing animationdata + :rtype: [{}, {}, ...] + + """ + logger.debug("animation.rest_animation(%s)", armature) + func = _parse_rest_action + return _parse_action(func, armature, options) + + +def _parse_action(func, armature, options): + """ + + :param func: + :param armature: + :param options: + + """ + animations = [] + logger.info("Parsing %d actions", len(data.actions)) + for action in data.actions: + logger.info("Parsing action %s", action.name) + animation = func(action, armature, options) + animations.append(animation) + return animations + + +def _parse_rest_action(action, armature, options): + """ + + :param action: + :param armature: + :param options: + + """ + end_frame = action.frame_range[1] + start_frame = action.frame_range[0] + frame_length = end_frame - start_frame + rot = armature.matrix_world.decompose()[1] + rotation_matrix = rot.to_matrix() + hierarchy = [] + parent_index = -1 + frame_step = options.get(constants.FRAME_STEP, 1) + fps = context.scene.render.fps + + start = int(start_frame) + end = int(end_frame / frame_step) + 1 + + for bone in armature.data.bones: + # I believe this was meant to skip control bones, may + # not be useful. needs more testing + if bone.use_deform is False: + logger.info("Skipping animation data for bone %s", bone.name) + continue + + logger.info("Parsing animation data for bone %s", bone.name) + + keys = [] + for frame in range(start, end): + computed_frame = frame * frame_step + pos, pchange = _position(bone, computed_frame, + action, armature.matrix_world) + rot, rchange = _rotation(bone, computed_frame, + action, rotation_matrix) + rot = _normalize_quaternion(rot) + + pos_x, pos_y, pos_z = pos.x, pos.z, -pos.y + rot_x, rot_y, rot_z, rot_w = rot.x, rot.z, -rot.y, rot.w + + if frame == start_frame: + + time = (frame * frame_step - start_frame) / fps + # @TODO: missing scale values + keyframe = { + constants.TIME: time, + constants.POS: [pos_x, pos_y, pos_z], + constants.ROT: [rot_x, rot_y, rot_z, rot_w], + constants.SCL: [1, 1, 1] + } + keys.append(keyframe) + + # END-FRAME: needs pos, rot and scl attributes + # with animation length (required frame) + + elif frame == end_frame / frame_step: + + time = frame_length / fps + keyframe = { + constants.TIME: time, + constants.POS: [pos_x, pos_y, pos_z], + constants.ROT: [rot_x, rot_y, rot_z, rot_w], + constants.SCL: [1, 1, 1] + } + keys.append(keyframe) + + # MIDDLE-FRAME: needs only one of the attributes, + # can be an empty frame (optional frame) + + elif pchange is True or rchange is True: + + time = (frame * frame_step - start_frame) / fps + + if pchange is True and rchange is True: + keyframe = { + constants.TIME: time, + constants.POS: [pos_x, pos_y, pos_z], + constants.ROT: [rot_x, rot_y, rot_z, rot_w] + } + elif pchange is True: + keyframe = { + constants.TIME: time, + constants.POS: [pos_x, pos_y, pos_z] + } + elif rchange is True: + keyframe = { + constants.TIME: time, + constants.ROT: [rot_x, rot_y, rot_z, rot_w] + } + + keys.append(keyframe) + + hierarchy.append({ + constants.KEYS: keys, + constants.PARENT: parent_index + }) + parent_index += 1 + + animation = { + constants.HIERARCHY: hierarchy, + constants.LENGTH: frame_length / fps, + constants.FPS: fps, + constants.NAME: action.name + } + + return animation + + +def _parse_pose_action(action, armature, options): + """ + + :param action: + :param armature: + :param options: + + """ + # @TODO: this seems to fail in batch mode meaning the + # user has to have th GUI open. need to improve + # this logic to allow batch processing, if Blender + # chooses to behave.... + current_context = context.area.type + context.area.type = 'DOPESHEET_EDITOR' + context.space_data.mode = 'ACTION' + context.area.spaces.active.action = action + + armature_matrix = armature.matrix_world + fps = context.scene.render.fps + + end_frame = action.frame_range[1] + start_frame = action.frame_range[0] + frame_length = end_frame - start_frame + + frame_step = options.get(constants.FRAME_STEP, 1) + used_frames = int(frame_length / frame_step) + 1 + + keys = [] + channels_location = [] + channels_rotation = [] + channels_scale = [] + + for pose_bone in armature.pose.bones: + logger.info("Processing channels for %s", + pose_bone.bone.name) + keys.append([]) + channels_location.append( + _find_channels(action, + pose_bone.bone, + 'location')) + channels_rotation.append( + _find_channels(action, + pose_bone.bone, + 'rotation_quaternion')) + channels_rotation.append( + _find_channels(action, + pose_bone.bone, + 'rotation_euler')) + channels_scale.append( + _find_channels(action, + pose_bone.bone, + 'scale')) + + frame_step = options[constants.FRAME_STEP] + frame_index_as_time = options[constants.FRAME_INDEX_AS_TIME] + for frame_index in range(0, used_frames): + if frame_index == used_frames - 1: + frame = end_frame + else: + frame = start_frame + frame_index * frame_step + + logger.info("Processing frame %d", frame) + + time = frame - start_frame + if frame_index_as_time is False: + time = time / fps + + context.scene.frame_set(frame) + + bone_index = 0 + + def has_keyframe_at(channels, frame): + """ + + :param channels: + :param frame: + + """ + def find_keyframe_at(channel, frame): + """ + + :param channel: + :param frame: + + """ + for keyframe in channel.keyframe_points: + if keyframe.co[0] == frame: + return keyframe + return None + + for channel in channels: + if not find_keyframe_at(channel, frame) is None: + return True + return False + + for pose_bone in armature.pose.bones: + + logger.info("Processing bone %s", pose_bone.bone.name) + if pose_bone.parent is None: + bone_matrix = armature_matrix * pose_bone.matrix + else: + parent_matrix = armature_matrix * pose_bone.parent.matrix + bone_matrix = armature_matrix * pose_bone.matrix + bone_matrix = parent_matrix.inverted() * bone_matrix + + pos, rot, scl = bone_matrix.decompose() + rot = _normalize_quaternion(rot) + + pchange = True or has_keyframe_at( + channels_location[bone_index], frame) + rchange = True or has_keyframe_at( + channels_rotation[bone_index], frame) + schange = True or has_keyframe_at( + channels_scale[bone_index], frame) + + pos = (pos.x, pos.z, -pos.y) + rot = (rot.x, rot.z, -rot.y, rot.w) + scl = (scl.x, scl.z, scl.y) + + keyframe = {constants.TIME: time} + if frame == start_frame or frame == end_frame: + keyframe.update({ + constants.POS: pos, + constants.ROT: rot, + constants.SCL: scl + }) + elif any([pchange, rchange, schange]): + if pchange is True: + keyframe[constants.POS] = pos + if rchange is True: + keyframe[constants.ROT] = rot + if schange is True: + keyframe[constants.SCL] = scl + + if len(keyframe.keys()) > 1: + logger.info("Recording keyframe data for %s %s", + pose_bone.bone.name, str(keyframe)) + keys[bone_index].append(keyframe) + else: + logger.info("No anim data to record for %s", + pose_bone.bone.name) + + bone_index += 1 + + hierarchy = [] + bone_index = 0 + for pose_bone in armature.pose.bones: + hierarchy.append({ + constants.PARENT: bone_index - 1, + constants.KEYS: keys[bone_index] + }) + bone_index += 1 + + if frame_index_as_time is False: + frame_length = frame_length / fps + + context.scene.frame_set(start_frame) + context.area.type = current_context + + animation = { + constants.HIERARCHY: hierarchy, + constants.LENGTH: frame_length, + constants.FPS: fps, + constants.NAME: action.name + } + + return animation + + +def _find_channels(action, bone, channel_type): + """ + + :param action: + :param bone: + :param channel_type: + + """ + result = [] + + if len(action.groups): + + group_index = -1 + for index, group in enumerate(action.groups): + if group.name == bone.name: + group_index = index + # @TODO: break? + + if group_index > -1: + for channel in action.groups[group_index].channels: + if channel_type in channel.data_path: + result.append(channel) + + else: + bone_label = '"%s"' % bone.name + for channel in action.fcurves: + data_path = [bone_label in channel.data_path, + channel_type in channel.data_path] + if all(data_path): + result.append(channel) + + return result + + +def _position(bone, frame, action, armature_matrix): + """ + + :param bone: + :param frame: + :param action: + :param armature_matrix: + + """ + + position = mathutils.Vector((0, 0, 0)) + change = False + + ngroups = len(action.groups) + + if ngroups > 0: + + index = 0 + + for i in range(ngroups): + if action.groups[i].name == bone.name: + index = i + + for channel in action.groups[index].channels: + if "location" in channel.data_path: + has_changed = _handle_position_channel( + channel, frame, position) + change = change or has_changed + + else: + + bone_label = '"%s"' % bone.name + + for channel in action.fcurves: + data_path = channel.data_path + if bone_label in data_path and "location" in data_path: + has_changed = _handle_position_channel( + channel, frame, position) + change = change or has_changed + + position = position * bone.matrix_local.inverted() + + if bone.parent is None: + + position.x += bone.head.x + position.y += bone.head.y + position.z += bone.head.z + + else: + + parent = bone.parent + + parent_matrix = parent.matrix_local.inverted() + diff = parent.tail_local - parent.head_local + + position.x += (bone.head * parent_matrix).x + diff.x + position.y += (bone.head * parent_matrix).y + diff.y + position.z += (bone.head * parent_matrix).z + diff.z + + return armature_matrix*position, change + + +def _rotation(bone, frame, action, armature_matrix): + """ + + :param bone: + :param frame: + :param action: + :param armature_matrix: + + """ + + # TODO: calculate rotation also from rotation_euler channels + + rotation = mathutils.Vector((0, 0, 0, 1)) + + change = False + + ngroups = len(action.groups) + + # animation grouped by bones + + if ngroups > 0: + + index = -1 + + for i in range(ngroups): + if action.groups[i].name == bone.name: + index = i + + if index > -1: + for channel in action.groups[index].channels: + if "quaternion" in channel.data_path: + has_changed = _handle_rotation_channel( + channel, frame, rotation) + change = change or has_changed + + # animation in raw fcurves + + else: + + bone_label = '"%s"' % bone.name + + for channel in action.fcurves: + data_path = channel.data_path + if bone_label in data_path and "quaternion" in data_path: + has_changed = _handle_rotation_channel( + channel, frame, rotation) + change = change or has_changed + + rot3 = rotation.to_3d() + rotation.xyz = rot3 * bone.matrix_local.inverted() + rotation.xyz = armature_matrix * rotation.xyz + + return rotation, change + + +def _handle_rotation_channel(channel, frame, rotation): + """ + + :param channel: + :param frame: + :param rotation: + + """ + + change = False + + if channel.array_index in [0, 1, 2, 3]: + + for keyframe in channel.keyframe_points: + if keyframe.co[0] == frame: + change = True + + value = channel.evaluate(frame) + + if channel.array_index == 1: + rotation.x = value + + elif channel.array_index == 2: + rotation.y = value + + elif channel.array_index == 3: + rotation.z = value + + elif channel.array_index == 0: + rotation.w = value + + return change + + +def _handle_position_channel(channel, frame, position): + """ + + :param channel: + :param frame: + :param position: + + """ + + change = False + + if channel.array_index in [0, 1, 2]: + for keyframe in channel.keyframe_points: + if keyframe.co[0] == frame: + change = True + + value = channel.evaluate(frame) + + if channel.array_index == 0: + position.x = value + + if channel.array_index == 1: + position.y = value + + if channel.array_index == 2: + position.z = value + + return change + + +def _quaternion_length(quat): + """Calculate the length of a quaternion + + :param quat: Blender quaternion object + :rtype: float + + """ + return math.sqrt(quat.x * quat.x + quat.y * quat.y + + quat.z * quat.z + quat.w * quat.w) + + +def _normalize_quaternion(quat): + """Normalize a quaternion + + :param quat: Blender quaternion object + :returns: generic quaternion enum object with normalized values + :rtype: object + + """ + enum = type('Enum', (), {'x': 0, 'y': 0, 'z': 0, 'w': 1}) + length = _quaternion_length(quat) + if length is not 0: + length = 1 / length + enum.x = quat.x * length + enum.y = quat.y * length + enum.z = quat.z * length + enum.w = quat.w * length + return enum diff --git a/utils/exporters/blender/addons/io_three/exporter/api/camera.py b/utils/exporters/blender/addons/io_three/exporter/api/camera.py index d34f001eb69049..6853a0a13ce376 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/camera.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/camera.py @@ -3,13 +3,25 @@ def _camera(func): + """ + + :param func: + + """ def inner(name, *args, **kwargs): + """ + + :param name: + :param *args: + :param **kwargs: + + """ if isinstance(name, types.Camera): camera = name else: - camera = data.cameras[name] + camera = data.cameras[name] return func(camera, *args, **kwargs) @@ -18,48 +30,96 @@ def inner(name, *args, **kwargs): @_camera def aspect(camera): - logger.debug('camera.aspect(%s)', camera) + """ + + :param camera: + :rtype: float + + """ + logger.debug("camera.aspect(%s)", camera) render = context.scene.render return render.resolution_x/render.resolution_y @_camera def bottom(camera): - logger.debug('camera.bottom(%s)', camera) + """ + + :param camera: + :rtype: float + + """ + logger.debug("camera.bottom(%s)", camera) return -(camera.angle_y * camera.ortho_scale) @_camera def far(camera): - logger.debug('camera.far(%s)', camera) + """ + + :param camera: + :rtype: float + + """ + logger.debug("camera.far(%s)", camera) return camera.clip_end @_camera def fov(camera): - logger.debug('camera.fov(%s)', camera) + """ + + :param camera: + :rtype: float + + """ + logger.debug("camera.fov(%s)", camera) return camera.lens @_camera def left(camera): - logger.debug('camera.left(%s)', camera) + """ + + :param camera: + :rtype: float + + """ + logger.debug("camera.left(%s)", camera) return -(camera.angle_x * camera.ortho_scale) @_camera def near(camera): - logger.debug('camera.near(%s)', camera) + """ + + :param camera: + :rtype: float + + """ + logger.debug("camera.near(%s)", camera) return camera.clip_start @_camera def right(camera): - logger.debug('camera.right(%s)', camera) + """ + + :param camera: + :rtype: float + + """ + logger.debug("camera.right(%s)", camera) return camera.angle_x * camera.ortho_scale @_camera def top(camera): - logger.debug('camera.top(%s)', camera) + """ + + :param camera: + :rtype: float + + """ + logger.debug("camera.top(%s)", camera) return camera.angle_y * camera.ortho_scale diff --git a/utils/exporters/blender/addons/io_three/exporter/api/image.py b/utils/exporters/blender/addons/io_three/exporter/api/image.py index 8ef45b21e4e514..c0581173fe7394 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/image.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/image.py @@ -4,13 +4,25 @@ def _image(func): + """ + + :param func: + + """ def inner(name, *args, **kwargs): + """ + + :param name: + :param *args: + :param **kwargs: + + """ if isinstance(name, types.Image): mesh = name else: - mesh = data.images[name] + mesh = data.images[name] return func(mesh, *args, **kwargs) @@ -18,11 +30,23 @@ def inner(name, *args, **kwargs): def file_name(image): - logger.debug('image.file_name(%s)', image) - return os.path.basename(file_path(image)) + """ + + :param image: + :rtype: str + + """ + logger.debug("image.file_name(%s)", image) + return os.path.basename(file_path(image)) @_image def file_path(image): - logger.debug('image.file_path(%s)', image) + """ + + :param image: + :rtype: str + + """ + logger.debug("image.file_path(%s)", image) return os.path.normpath(image.filepath_from_user()) diff --git a/utils/exporters/blender/addons/io_three/exporter/api/light.py b/utils/exporters/blender/addons/io_three/exporter/api/light.py index 1668a6aa6459f8..33c5fa86dd89b3 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/light.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/light.py @@ -1,15 +1,27 @@ -from bpy import data, types +from bpy import data, types from .. import utilities, logger def _lamp(func): + """ + + :param func: + + """ def inner(name, *args, **kwargs): + """ + + :param name: + :param *args: + :param **kwargs: + + """ if isinstance(name, types.Lamp): lamp = name else: - lamp = data.lamps[name] + lamp = data.lamps[name] return func(lamp, *args, **kwargs) @@ -18,24 +30,48 @@ def inner(name, *args, **kwargs): @_lamp def angle(lamp): - logger.debug('light.angle(%s)', lamp) + """ + + :param lamp: + :rtype: float + + """ + logger.debug("light.angle(%s)", lamp) return lamp.spot_size @_lamp def color(lamp): - logger.debug('light.color(%s)', lamp) + """ + + :param lamp: + :rtype: int + + """ + logger.debug("light.color(%s)", lamp) colour = (lamp.color.r, lamp.color.g, lamp.color.b) return utilities.rgb2int(colour) @_lamp def distance(lamp): - logger.debug('light.distance(%s)', lamp) + """ + + :param lamp: + :rtype: float + + """ + logger.debug("light.distance(%s)", lamp) return lamp.distance @_lamp def intensity(lamp): - logger.debug('light.intensity(%s)', lamp) + """ + + :param lamp: + :rtype: float + + """ + logger.debug("light.intensity(%s)", lamp) return round(lamp.energy, 2) diff --git a/utils/exporters/blender/addons/io_three/exporter/api/material.py b/utils/exporters/blender/addons/io_three/exporter/api/material.py index a3e6bcb985e8b5..df81eaef5adf4e 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/material.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/material.py @@ -4,13 +4,25 @@ def _material(func): + """ + + :param func: + + """ def inner(name, *args, **kwargs): + """ + + :param name: + :param *args: + :param **kwargs: + + """ if isinstance(name, types.Material): material = name else: - material = data.materials[name] + material = data.materials[name] return func(material, *args, **kwargs) @@ -19,8 +31,15 @@ def inner(name, *args, **kwargs): @_material def ambient_color(material): - logger.debug('material.ambient_color(%s)', material) - diffuse = diffuse_color(material) + """ + + :param material: + :return: rgb value + :rtype: tuple + + """ + logger.debug("material.ambient_color(%s)", material) + diffuse = diffuse_color(material) return (material.ambient * diffuse[0], material.ambient * diffuse[1], material.ambient * diffuse[2]) @@ -28,18 +47,30 @@ def ambient_color(material): @_material def blending(material): - logger.debug('material.blending(%s)', material) + """ + + :param material: + :return: THREE_blending_type value + + """ + logger.debug("material.blending(%s)", material) try: blend = material.THREE_blending_type except AttributeError: - logger.debug('No THREE_blending_type attribute found') - blend = constants.NORMAL_BLENDING + logger.debug("No THREE_blending_type attribute found") + blend = constants.NORMAL_BLENDING return blend @_material def bump_map(material): - logger.debug('material.bump_map(%s)', material) + """ + + :param material: + :return: texture node for bump + + """ + logger.debug("material.bump_map(%s)", material) for texture in _valid_textures(material): if texture.use_map_normal and not \ texture.texture.use_normal_map: @@ -48,34 +79,61 @@ def bump_map(material): @_material def bump_scale(material): + """ + + :param material: + :rtype: float + + """ return normal_scale(material) @_material def depth_test(material): - logger.debug('material.depth_test(%s)', material) + """ + + :param material: + :return: THREE_depth_test value + :rtype: bool + + """ + logger.debug("material.depth_test(%s)", material) try: test = material.THREE_depth_test except AttributeError: - logger.debug('No THREE_depth_test attribute found') + logger.debug("No THREE_depth_test attribute found") test = True return test @_material def depth_write(material): - logger.debug('material.depth_write(%s)', material) + """ + + :param material: + :return: THREE_depth_write value + :rtype: bool + + """ + logger.debug("material.depth_write(%s)", material) try: write = material.THREE_depth_write except AttributeError: - logger.debug('No THREE_depth_write attribute found') + logger.debug("No THREE_depth_write attribute found") write = True return write @_material def diffuse_color(material): - logger.debug('material.diffuse_color(%s)', material) + """ + + :param material: + :return: rgb value + :rtype: tuple + + """ + logger.debug("material.diffuse_color(%s)", material) return (material.diffuse_intensity * material.diffuse_color[0], material.diffuse_intensity * material.diffuse_color[1], material.diffuse_intensity * material.diffuse_color[2]) @@ -83,7 +141,13 @@ def diffuse_color(material): @_material def diffuse_map(material): - logger.debug('material.diffuse_map(%s)', material) + """ + + :param material: + :return: texture node for map + + """ + logger.debug("material.diffuse_map(%s)", material) for texture in _valid_textures(material): if texture.use_map_color_diffuse and not \ texture.blend_type == MULTIPLY: @@ -92,8 +156,15 @@ def diffuse_map(material): @_material def emissive_color(material): - logger.debug('material.emissive_color(%s)', material) - diffuse = diffuse_color(material) + """ + + :param material: + :return: rgb value + :rtype: tuple + + """ + logger.debug("material.emissive_color(%s)", material) + diffuse = diffuse_color(material) return (material.emit * diffuse[0], material.emit * diffuse[1], material.emit * diffuse[2]) @@ -101,8 +172,14 @@ def emissive_color(material): @_material def light_map(material): - logger.debug('material.light_map(%s)', material) - for texture in _valid_textures(material): + """ + + :param material: + :return: texture node for light maps + + """ + logger.debug("material.light_map(%s)", material) + for texture in _valid_textures(material, strict_use=False): if texture.use_map_color_diffuse and \ texture.blend_type == MULTIPLY: return texture.texture @@ -110,7 +187,13 @@ def light_map(material): @_material def normal_scale(material): - logger.debug('material.normal_scale(%s)', material) + """ + + :param material: + :rtype: float + + """ + logger.debug("material.normal_scale(%s)", material) for texture in _valid_textures(material): if texture.use_map_normal: return texture.normal_factor @@ -118,22 +201,40 @@ def normal_scale(material): @_material def normal_map(material): - logger.debug('material.normal_map(%s)', material) + """ + + :param material: + :return: texture node for normals + + """ + logger.debug("material.normal_map(%s)", material) for texture in _valid_textures(material): if texture.use_map_normal and \ texture.texture.use_normal_map: return texture.texture - + @_material def opacity(material): - logger.debug('material.opacity(%s)', material) - return round( material.alpha, 2 ); + """ + + :param material: + :rtype: float + + """ + logger.debug("material.opacity(%s)", material) + return round(material.alpha, 2) @_material def shading(material): - logger.debug('material.shading(%s)', material) + """ + + :param material: + :return: shading type (phong or lambert) + + """ + logger.debug("material.shading(%s)", material) dispatch = { True: constants.PHONG, False: constants.LAMBERT @@ -144,21 +245,40 @@ def shading(material): @_material def specular_coef(material): - logger.debug('material.specular_coef(%s)', material) + """ + + :param material: + :rtype: float + + """ + logger.debug("material.specular_coef(%s)", material) return material.specular_hardness - + @_material def specular_color(material): - logger.debug('material.specular_color(%s)', material) + """ + + :param material: + :return: rgb value + :rtype: tuple + + """ + logger.debug("material.specular_color(%s)", material) return (material.specular_intensity * material.specular_color[0], material.specular_intensity * material.specular_color[1], material.specular_intensity * material.specular_color[2]) - + @_material def specular_map(material): - logger.debug('material.specular_map(%s)', material) + """ + + :param material: + :return: texture node for specular + + """ + logger.debug("material.specular_map(%s)", material) for texture in _valid_textures(material): if texture.use_map_specular: return texture.texture @@ -166,13 +286,25 @@ def specular_map(material): @_material def transparent(material): - logger.debug('material.transparent(%s)', material) + """ + + :param material: + :rtype: bool + + """ + logger.debug("material.transparent(%s)", material) return material.use_transparency @_material def type(material): - logger.debug('material.type(%s)', material) + """ + + :param material: + :return: THREE compatible shader type + + """ + logger.debug("material.type(%s)", material) if material.diffuse_shader != 'LAMBERT': material_type = constants.BASIC elif material.specular_intensity > 0: @@ -185,23 +317,42 @@ def type(material): @_material def use_vertex_colors(material): - logger.debug('material.use_vertex_colors(%s)', material) + """ + + :param material: + :rtype: bool + + """ + logger.debug("material.use_vertex_colors(%s)", material) return material.use_vertex_color_paint def used_materials(): - logger.debug('material.used_materials()') + """ + + :return: list of materials that are in use + :rtype: generator + + """ + logger.debug("material.used_materials()") for material in data.materials: if material.users > 0: yield material.name @_material def visible(material): - logger.debug('material.visible(%s)', material) + """ + + :param material: + :return: THREE_visible value + :rtype: bool + + """ + logger.debug("material.visible(%s)", material) try: vis = material.THREE_visible except AttributeError: - logger.debug('No THREE_visible attribute found') + logger.debug("No THREE_visible attribute found") vis = True return vis @@ -209,13 +360,31 @@ def visible(material): @_material def wireframe(material): - logger.debug('material.wireframe(%s)', material) + """ + + :param material: + :rtype: bool + + """ + logger.debug("material.wireframe(%s)", material) return material.type == WIRE - -def _valid_textures(material): + +def _valid_textures(material, strict_use=True): + """ + + :param material: + :rtype: generator + + """ for texture in material.texture_slots: - if not texture: continue - if texture.texture.type != IMAGE: continue - logger.debug('Valid texture found %s', texture) + if not texture: + continue + if strict_use: + in_use = texture.use + else: + in_use = True + if texture.texture.type != IMAGE or not in_use: + continue + logger.debug("Valid texture found %s", texture) yield texture diff --git a/utils/exporters/blender/addons/io_three/exporter/api/mesh.py b/utils/exporters/blender/addons/io_three/exporter/api/mesh.py index 70ad1bf2c9d942..6373e43040cb17 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/mesh.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/mesh.py @@ -1,19 +1,36 @@ +""" +Blender API for querying mesh data. Animation data is also +handled here since Three.js associates the animation (skeletal, +morph targets) with the geometry nodes. +""" + import operator -import mathutils from bpy import data, types, context -from . import material, texture +from . import material, texture, animation from . import object as object_ from .. import constants, utilities, logger, exceptions def _mesh(func): + """ + + :param func: + + """ def inner(name, *args, **kwargs): + """ + + :param name: + :param *args: + :param **kwargs: + + """ if isinstance(name, types.Mesh): mesh = name else: - mesh = data.meshes[name] + mesh = data.meshes[name] return func(mesh, *args, **kwargs) @@ -21,252 +38,290 @@ def inner(name, *args, **kwargs): @_mesh -def animation(mesh, options): - logger.debug('mesh.animation(%s, %s)', mesh, options) +def skeletal_animation(mesh, options): + """ + + :param mesh: + :param options: + :rtype: [] + + """ + logger.debug("mesh.animation(%s, %s)", mesh, options) armature = _armature(mesh) - if armature and armature.animation_data: - return _skeletal_animations(armature, options) + + if not armature: + logger.warning("No armature found (%s)", mesh) + return [] + + anim_type = options.get(constants.ANIMATION) +# pose_position = armature.data.pose_position + dispatch = { + constants.POSE: animation.pose_animation, + constants.REST: animation.rest_animation + } + + func = dispatch[anim_type] +# armature.data.pose_position = anim_type.upper() + animations = func(armature, options) +# armature.data.pose_position = pose_position + + return animations @_mesh -def bones(mesh): - logger.debug('mesh.bones(%s)', mesh) - armature = _armature(mesh) - if not armature: return +def bones(mesh, options): + """ - bones = [] - bone_map = {} - bone_count = 0 - bone_index_rel = 0 + :param mesh: + :param options: + :rtype: [], {} - for bone in armature.data.bones: - logger.info('Parsing bone %s', bone.name) + """ + logger.debug("mesh.bones(%s)", mesh) + armature = _armature(mesh) - if bone.parent is None or bone.parent.use_deform is False: - bone_pos = bone.head_local - bone_index = -1 - else: - bone_pos = bone.head_local - bone.parent.head_local - bone_index = 0 - index = 0 - for parent in armature.data.bones: - if parent.name == bone.parent.name: - bone_index = bone_map.get(index) - index += 1 + if not armature: + return [], {} - bone_world_pos = armature.matrix_world * bone_pos - x_axis = bone_world_pos.x - y_axis = bone_world_pos.z - z_axis = -bone_world_pos.y + anim_type = options.get(constants.ANIMATION) +# pose_position = armature.data.pose_position - if bone.use_deform: - logger.debug('Adding bone %s at: %s, %s', - bone.name, bone_index, bone_index_rel) - bone_map[bone_count] = bone_index_rel - bone_index_rel += 1 - bones.append({ - constants.PARENT: bone_index, - constants.NAME: bone.name, - constants.POS: (x_axis, y_axis, z_axis), - constants.ROTQ: (0,0,0,1) - }) - else: - logger.debug('Ignoring bone %s at: %s, %s', - bone.name, bone_index, bone_index_rel) + if anim_type == constants.OFF: + logger.info("Animation type not set, defaulting " + "to using REST position for the armature.") + func = _rest_bones +# armature.data.pose_position = "REST" + else: + dispatch = { + constants.REST: _rest_bones, + constants.POSE: _pose_bones + } + logger.info("Using %s for the armature", anim_type) + func = dispatch[anim_type] +# armature.data.pose_position = anim_type.upper() - bone_count += 1 + bones_, bone_map = func(armature) +# armature.data.pose_position = pose_position - return (bones, bone_map) + return (bones_, bone_map) @_mesh -def buffer_normal(mesh, options): +def buffer_normal(mesh): + """ + + :param mesh: + :rtype: [] + + """ normals_ = [] - round_off, round_val = utilities.rounding(options) for face in mesh.tessfaces: vert_count = len(face.vertices) if vert_count is not 3: - msg = 'Non-triangulated face detected' + msg = "Non-triangulated face detected" raise exceptions.BufferGeometryError(msg) for vertex_index in face.vertices: normal = mesh.vertices[vertex_index].normal vector = (normal.x, normal.y, normal.z) - if round_off: - vector = utilities.round_off(vector, round_val) - normals_.extend(vector) return normals_ +@_mesh +def buffer_position(mesh): + """ + :param mesh: + :rtype: [] -@_mesh -def buffer_position(mesh, options): + """ position = [] - round_off, round_val = utilities.rounding(options) for face in mesh.tessfaces: vert_count = len(face.vertices) if vert_count is not 3: - msg = 'Non-triangulated face detected' + msg = "Non-triangulated face detected" raise exceptions.BufferGeometryError(msg) for vertex_index in face.vertices: vertex = mesh.vertices[vertex_index] vector = (vertex.co.x, vertex.co.y, vertex.co.z) - if round_off: - vector = utilities.round_off(vector, round_val) - position.extend(vector) return position @_mesh -def buffer_uv(mesh, options): +def buffer_uv(mesh): + """ + + :param mesh: + :rtype: [] + + """ + uvs_ = [] if len(mesh.uv_layers) is 0: - return + return uvs_ elif len(mesh.uv_layers) > 1: # if memory serves me correctly buffer geometry # only uses one UV layer - logger.warning('%s has more than 1 UV layer', mesh.name ) + logger.warning("%s has more than 1 UV layer", mesh.name) + + for uv_data in mesh.uv_layers[0].data: + uv_tuple = (uv_data.uv[0], uv_data.uv[1]) + uvs_.extend(uv_tuple) - round_off, round_val = utilities.rounding(options) - uvs_ = [] - for uv in mesh.uv_layers[0].data: - uv = (uv.uv[0], uv.uv[1]) - if round_off: - uv = utilities.round_off(uv, round_val) - uvs_.extend(uv) - return uvs_ + @_mesh def faces(mesh, options): - logger.debug('mesh.faces(%s, %s)', mesh, options) - vertex_uv = len(mesh.uv_textures) > 0 - has_colors = len(mesh.vertex_colors) > 0 - logger.info('Has UVs = %s', vertex_uv) - logger.info('Has vertex colours = %s', has_colors) + """ + :param mesh: + :param options: - round_off, round_val = utilities.rounding(options) - if round_off: - logger.debug('Rounding off of vectors set to %s', round_off) + """ + logger.debug("mesh.faces(%s, %s)", mesh, options) + vertex_uv = len(mesh.uv_textures) > 0 + has_colors = len(mesh.vertex_colors) > 0 + logger.info("Has UVs = %s", vertex_uv) + logger.info("Has vertex colours = %s", has_colors) opt_colours = options[constants.COLORS] and has_colors opt_uvs = options[constants.UVS] and vertex_uv opt_materials = options.get(constants.FACE_MATERIALS) opt_normals = options[constants.NORMALS] - logger.debug('Vertex colours enabled = %s', opt_colours) - logger.debug('UVS enabled = %s', opt_uvs) - logger.debug('Materials enabled = %s', opt_materials) - logger.debug('Normals enabled = %s', opt_normals) + logger.debug("Vertex colours enabled = %s", opt_colours) + logger.debug("UVS enabled = %s", opt_uvs) + logger.debug("Materials enabled = %s", opt_materials) + logger.debug("Normals enabled = %s", opt_normals) - uv_layers = _uvs(mesh, options) if opt_uvs else None - vertex_normals = _normals(mesh, options) if opt_normals else None + uv_layers = _uvs(mesh) if opt_uvs else None + vertex_normals = _normals(mesh) if opt_normals else None vertex_colours = vertex_colors(mesh) if opt_colours else None - face_data = [] + faces_data = [] + + colour_indices = {} + if vertex_colours: + logger.debug("Indexing colours") + for index, colour in enumerate(vertex_colours): + colour_indices[str(colour)] = index + + normal_indices = {} + if vertex_normals: + logger.debug("Indexing normals") + for index, normal in enumerate(vertex_normals): + normal_indices[str(normal)] = index - logger.info('Parsing %d faces', len(mesh.tessfaces)) + logger.info("Parsing %d faces", len(mesh.tessfaces)) for face in mesh.tessfaces: vert_count = len(face.vertices) if vert_count not in (3, 4): - logger.error('%d vertices for face %d detected', - vert_count, face.index) - raise exceptions.NGonError('ngons are not supported') + logger.error("%d vertices for face %d detected", + vert_count, + face.index) + raise exceptions.NGonError("ngons are not supported") - materials = face.material_index is not None and opt_materials + mat_index = face.material_index is not None and opt_materials mask = { constants.QUAD: vert_count is 4, - constants.MATERIALS: materials, - constants.UVS: opt_uvs, - constants.NORMALS: opt_normals, - constants.COLORS: opt_colours + constants.MATERIALS: mat_index, + constants.UVS: False, + constants.NORMALS: False, + constants.COLORS: False } - face_data.append(utilities.bit_mask(mask)) - + face_data = [] + face_data.extend([v for v in face.vertices]) - + if mask[constants.MATERIALS]: face_data.append(face.material_index) - - if mask[constants.UVS] and uv_layers: + # @TODO: this needs the same optimization as what + # was done for colours and normals + if uv_layers: for index, uv_layer in enumerate(uv_layers): layer = mesh.tessface_uv_textures[index] for uv_data in layer.data[face.index].uv: - uv = (uv_data[0], uv_data[1]) - if round_off: - uv = utilities.round_off(uv, round_val) - face_data.append(uv_layer.index(uv)) + uv_tuple = (uv_data[0], uv_data[1]) + face_data.append(uv_layer.index(uv_tuple)) + mask[constants.UVS] = True - if mask[constants.NORMALS] and vertex_normals: + if vertex_normals: for vertex in face.vertices: normal = mesh.vertices[vertex].normal normal = (normal.x, normal.y, normal.z) - if round_off: - normal = utilities.round_off(normal, round_val) - face_data.append(vertex_normals.index(normal)) - - if mask[constants.COLORS]: + face_data.append(normal_indices[str(normal)]) + mask[constants.NORMALS] = True + + if vertex_colours: colours = mesh.tessface_vertex_colors.active.data[face.index] for each in (colours.color1, colours.color2, colours.color3): each = utilities.rgb2int(each) - face_data.append(vertex_colours.index(each)) + face_data.append(colour_indices[str(each)]) + mask[constants.COLORS] = True if mask[constants.QUAD]: colour = utilities.rgb2int(colours.color4) - face_data.append(vertex_colours.index(colour)) + face_data.append(colour_indices[str(colour)]) + + face_data.insert(0, utilities.bit_mask(mask)) + faces_data.extend(face_data) + + return faces_data - return face_data - @_mesh def morph_targets(mesh, options): - logger.debug('mesh.morph_targets(%s, %s)', mesh, options) - #@TODO: consider an attribute for the meshes for determining - # morphs, which would save on so much overhead + """ + + :param mesh: + :param options: + + """ + logger.debug("mesh.morph_targets(%s, %s)", mesh, options) obj = object_.objects_using_mesh(mesh)[0] original_frame = context.scene.frame_current frame_step = options.get(constants.FRAME_STEP, 1) scene_frames = range(context.scene.frame_start, - context.scene.frame_end+1, frame_step) + context.scene.frame_end+1, + frame_step) morphs = [] + for frame in scene_frames: - logger.info('Processing data at frame %d', frame) + logger.info("Processing data at frame %d", frame) context.scene.frame_set(frame, 0.0) morphs.append([]) - vertices = object_.extract_mesh(obj, options).vertices[:] + vertices_ = object_.extract_mesh(obj, options).vertices[:] + + for vertex in vertices_: + morphs[-1].extend([vertex.co.x, vertex.co.y, vertex.co.z]) - for vertex in vertices: - vectors = [round(vertex.co.x, 6), round(vertex.co.y, 6), - round(vertex.co.z, 6)] - morphs[-1].extend(vectors) - context.scene.frame_set(original_frame, 0.0) morphs_detected = False for index, each in enumerate(morphs): - if index is 0: continue + if index is 0: + continue morphs_detected = morphs[index-1] != each - if morphs_detected: - logger.info('Valid morph target data detected') + if morphs_detected: + logger.info("Valid morph target data detected") break - else: - logger.info('No valid morph data detected') - return + else: + logger.info("No valid morph data detected") + return [] manifest = [] - for index,morph in enumerate(morphs): + for index, morph in enumerate(morphs): manifest.append({ constants.NAME: 'animation_%06d' % index, constants.VERTICES: morph @@ -277,25 +332,31 @@ def morph_targets(mesh, options): @_mesh def materials(mesh, options): - logger.debug('mesh.materials(%s, %s)', mesh, options) + """ + + :param mesh: + :param options: + + """ + logger.debug("mesh.materials(%s, %s)", mesh, options) indices = set([face.material_index for face in mesh.tessfaces]) material_sets = [(mesh.materials[index], index) for index in indices] - materials = [] + materials_ = [] maps = options.get(constants.MAPS) mix = options.get(constants.MIX_COLORS) use_colors = options.get(constants.COLORS) - logger.info('Colour mix is set to %s', mix) - logger.info('Vertex colours set to %s', use_colors) + logger.info("Colour mix is set to %s", mix) + logger.info("Vertex colours set to %s", use_colors) for mat, index in material_sets: try: dbg_color = constants.DBG_COLORS[index] except IndexError: dbg_color = constants.DBG_COLORS[0] - - logger.info('Compiling attributes for %s', mat.name) + + logger.info("Compiling attributes for %s", mat.name) attributes = { constants.COLOR_AMBIENT: material.ambient_color(mat), constants.COLOR_EMISSIVE: material.emissive_color(mat), @@ -315,148 +376,191 @@ def materials(mesh, options): if use_colors: colors = material.use_vertex_colors(mat) attributes[constants.VERTEX_COLORS] = colors - + if (use_colors and mix) or (not use_colors): colors = material.diffuse_color(mat) attributes[constants.COLOR_DIFFUSE] = colors if attributes[constants.SHADING] == constants.PHONG: - logger.info('Adding specular attributes') + logger.info("Adding specular attributes") attributes.update({ constants.SPECULAR_COEF: material.specular_coef(mat), constants.COLOR_SPECULAR: material.specular_color(mat) }) if mesh.show_double_sided: - logger.info('Double sided is on') + logger.info("Double sided is on") attributes[constants.DOUBLE_SIDED] = True - materials.append(attributes) + materials_.append(attributes) - if not maps: continue + if not maps: + continue diffuse = _diffuse_map(mat) if diffuse: - logger.info('Diffuse map found') + logger.info("Diffuse map found") attributes.update(diffuse) - + light = _light_map(mat) if light: - logger.info('Light map found') + logger.info("Light map found") attributes.update(light) specular = _specular_map(mat) if specular: - logger.info('Specular map found') + logger.info("Specular map found") attributes.update(specular) if attributes[constants.SHADING] == constants.PHONG: normal = _normal_map(mat) if normal: - logger.info('Normal map found') + logger.info("Normal map found") attributes.update(normal) bump = _bump_map(mat) if bump: - logger.info('Bump map found') + logger.info("Bump map found") attributes.update(bump) - return materials + return materials_ @_mesh -def normals(mesh, options): - logger.debug('mesh.normals(%s, %s)', mesh, options) - flattened = [] +def normals(mesh): + """ - for vector in _normals(mesh, options): - flattened.extend(vector) + :param mesh: + :rtype: [] - return flattened + """ + logger.debug("mesh.normals(%s)", mesh) + normal_vectors = [] + + for vector in _normals(mesh): + normal_vectors.extend(vector) + + return normal_vectors @_mesh def skin_weights(mesh, bone_map, influences): - logger.debug('mesh.skin_weights(%s)', mesh) + """ + + :param mesh: + :param bone_map: + :param influences: + + """ + logger.debug("mesh.skin_weights(%s)", mesh) return _skinning_data(mesh, bone_map, influences, 1) @_mesh def skin_indices(mesh, bone_map, influences): - logger.debug('mesh.skin_indices(%s)', mesh) + """ + + :param mesh: + :param bone_map: + :param influences: + + """ + logger.debug("mesh.skin_indices(%s)", mesh) return _skinning_data(mesh, bone_map, influences, 0) @_mesh def texture_registration(mesh): - logger.debug('mesh.texture_registration(%s)', mesh) - materials = mesh.materials or [] + """ + + :param mesh: + + """ + logger.debug("mesh.texture_registration(%s)", mesh) + materials_ = mesh.materials or [] registration = {} funcs = ( - (constants.MAP_DIFFUSE, material.diffuse_map), + (constants.MAP_DIFFUSE, material.diffuse_map), (constants.SPECULAR_MAP, material.specular_map), - (constants.LIGHT_MAP, material.light_map), - (constants.BUMP_MAP, material.bump_map), + (constants.LIGHT_MAP, material.light_map), + (constants.BUMP_MAP, material.bump_map), (constants.NORMAL_MAP, material.normal_map) ) - + def _registration(file_path, file_name): + """ + + :param file_path: + :param file_name: + + """ return { 'file_path': file_path, 'file_name': file_name, 'maps': [] } - logger.info('found %d materials', len(materials)) - for mat in materials: + logger.info("found %d materials", len(materials_)) + for mat in materials_: for (key, func) in funcs: tex = func(mat) - if tex is None: continue + if tex is None: + continue - logger.info('%s has texture %s', key, tex.name) + logger.info("%s has texture %s", key, tex.name) file_path = texture.file_path(tex) file_name = texture.file_name(tex) - hash_ = utilities.hash(file_path) - - reg = registration.setdefault(hash_, + reg = registration.setdefault( + utilities.hash(file_path), _registration(file_path, file_name)) - reg['maps'].append(key) + reg["maps"].append(key) return registration @_mesh -def uvs(mesh, options): - logger.debug('mesh.uvs(%s, %s)', mesh, options) - uvs = [] - for layer in _uvs(mesh, options): - uvs.append([]) - logger.info('Parsing UV layer %d', len(uvs)) +def uvs(mesh): + """ + + :param mesh: + :rtype: [] + + """ + logger.debug("mesh.uvs(%s)", mesh) + uvs_ = [] + for layer in _uvs(mesh): + uvs_.append([]) + logger.info("Parsing UV layer %d", len(uvs_)) for pair in layer: - uvs[-1].extend(pair) - return uvs + uvs_[-1].extend(pair) + return uvs_ @_mesh def vertex_colors(mesh): - logger.debug('mesh.vertex_colors(%s)', mesh) + """ + + :param mesh: + + """ + logger.debug("mesh.vertex_colors(%s)", mesh) vertex_colours = [] try: vertex_colour = mesh.tessface_vertex_colors.active.data except AttributeError: - logger.info('No vertex colours found') + logger.info("No vertex colours found") return for face in mesh.tessfaces: colours = (vertex_colour[face.index].color1, - vertex_colour[face.index].color2, - vertex_colour[face.index].color3, - vertex_colour[face.index].color4) + vertex_colour[face.index].color2, + vertex_colour[face.index].color3, + vertex_colour[face.index].color4) for colour in colours: colour = utilities.rgb2int((colour.r, colour.g, colour.b)) @@ -468,37 +572,42 @@ def vertex_colors(mesh): @_mesh -def vertices(mesh, options): - logger.debug('mesh.vertices(%s, %s)', mesh, options) - vertices = [] +def vertices(mesh): + """ - round_off, round_val = utilities.rounding(options) + :param mesh: + :rtype: [] - for vertex in mesh.vertices: - vector = (vertex.co.x, vertex.co.y, vertex.co.z) - if round_off: - vector = utilities.round_off(vector, round_val) + """ + logger.debug("mesh.vertices(%s)", mesh) + vertices_ = [] - vertices.extend(vector) + for vertex in mesh.vertices: + vertices_.extend((vertex.co.x, vertex.co.y, vertex.co.z)) - return vertices + return vertices_ def _normal_map(mat): + """ + + :param mat: + + """ tex = material.normal_map(mat) if tex is None: return - logger.info('Found normal texture map %s', tex.name) + logger.info("Found normal texture map %s", tex.name) normal = { - constants.MAP_NORMAL: + constants.MAP_NORMAL: texture.file_name(tex), constants.MAP_NORMAL_FACTOR: - material.normal_scale(mat), - constants.MAP_NORMAL_ANISOTROPY: + material.normal_scale(mat), + constants.MAP_NORMAL_ANISOTROPY: texture.anisotropy(tex), - constants.MAP_NORMAL_WRAP: texture.wrap(tex), + constants.MAP_NORMAL_WRAP: texture.wrap(tex), constants.MAP_NORMAL_REPEAT: texture.repeat(tex) } @@ -506,75 +615,95 @@ def _normal_map(mat): def _bump_map(mat): + """ + + :param mat: + + """ tex = material.bump_map(mat) if tex is None: return - logger.info('Found bump texture map %s', tex.name) + logger.info("Found bump texture map %s", tex.name) bump = { - constants.MAP_BUMP: + constants.MAP_BUMP: texture.file_name(tex), - constants.MAP_BUMP_ANISOTROPY: + constants.MAP_BUMP_ANISOTROPY: texture.anisotropy(tex), constants.MAP_BUMP_WRAP: texture.wrap(tex), constants.MAP_BUMP_REPEAT: texture.repeat(tex), constants.MAP_BUMP_SCALE: - material.bump_scale(mat), + material.bump_scale(mat), } return bump def _specular_map(mat): + """ + + :param mat: + + """ tex = material.specular_map(mat) if tex is None: - return + return - logger.info('Found specular texture map %s', tex.name) + logger.info("Found specular texture map %s", tex.name) specular = { - constants.MAP_SPECULAR: + constants.MAP_SPECULAR: texture.file_name(tex), - constants.MAP_SPECULAR_ANISOTROPY: + constants.MAP_SPECULAR_ANISOTROPY: texture.anisotropy(tex), constants.MAP_SPECULAR_WRAP: texture.wrap(tex), constants.MAP_SPECULAR_REPEAT: texture.repeat(tex) } - return specular + return specular def _light_map(mat): + """ + + :param mat: + + """ tex = material.light_map(mat) if tex is None: - return + return - logger.info('Found light texture map %s', tex.name) + logger.info("Found light texture map %s", tex.name) light = { - constants.MAP_LIGHT: + constants.MAP_LIGHT: texture.file_name(tex), - constants.MAP_LIGHT_ANISOTROPY: + constants.MAP_LIGHT_ANISOTROPY: texture.anisotropy(tex), constants.MAP_LIGHT_WRAP: texture.wrap(tex), constants.MAP_LIGHT_REPEAT: texture.repeat(tex) } - return light + return light def _diffuse_map(mat): + """ + + :param mat: + + """ tex = material.diffuse_map(mat) if tex is None: - return + return - logger.info('Found diffuse texture map %s', tex.name) + logger.info("Found diffuse texture map %s", tex.name) diffuse = { - constants.MAP_DIFFUSE: + constants.MAP_DIFFUSE: texture.file_name(tex), - constants.MAP_DIFFUSE_ANISOTROPY: + constants.MAP_DIFFUSE_ANISOTROPY: texture.anisotropy(tex), constants.MAP_DIFFUSE_WRAP: texture.wrap(tex), constants.MAP_DIFFUSE_REPEAT: texture.repeat(tex) @@ -583,60 +712,84 @@ def _diffuse_map(mat): return diffuse -def _normals(mesh, options): +def _normals(mesh): + """ + + :param mesh: + :rtype: [] + + """ vectors = [] - round_off, round_val = utilities.rounding(options) + vectors_ = {} for face in mesh.tessfaces: for vertex_index in face.vertices: normal = mesh.vertices[vertex_index].normal vector = (normal.x, normal.y, normal.z) - if round_off: - vector = utilities.round_off(vector, round_val) - if vector not in vectors: + str_vec = str(vector) + try: + vectors_[str_vec] + except KeyError: vectors.append(vector) + vectors_[str_vec] = True return vectors -def _uvs(mesh, options): +def _uvs(mesh): + """ + + :param mesh: + + """ uv_layers = [] - round_off, round_val = utilities.rounding(options) for layer in mesh.uv_layers: uv_layers.append([]) - for uv in layer.data: - uv = (uv.uv[0], uv.uv[1]) - if round_off: - uv = utilities.round_off(uv, round_val) + for uv_data in layer.data: + uv_tuple = (uv_data.uv[0], uv_data.uv[1]) - if uv not in uv_layers[-1]: - uv_layers[-1].append(uv) + if uv_tuple not in uv_layers[-1]: + uv_layers[-1].append(uv_tuple) return uv_layers def _armature(mesh): + """ + + :param mesh: + + """ obj = object_.objects_using_mesh(mesh)[0] armature = obj.find_armature() if armature: - logger.info('Found armature %s for %s', armature.name, obj.name) + logger.info("Found armature %s for %s", armature.name, obj.name) else: - logger.info('Found no armature for %s', obj.name) + logger.info("Found no armature for %s", obj.name) return armature def _skinning_data(mesh, bone_map, influences, array_index): + """ + + :param mesh: + :param bone_map: + :param influences: + :param array_index: + + """ armature = _armature(mesh) - if not armature: return + manifest = [] + if not armature: + return manifest obj = object_.objects_using_mesh(mesh)[0] - logger.debug('Skinned object found %s', obj.name) + logger.debug("Skinned object found %s", obj.name) - manifest = [] for vertex in mesh.vertices: bone_array = [] for group in vertex.groups: @@ -648,9 +801,9 @@ def _skinning_data(mesh, bone_map, influences, array_index): if index >= len(bone_array): manifest.append(0) continue - - for bone_index, bone in enumerate(armature.data.bones): - if bone.name != obj.vertex_groups[bone_array[index][0]].name: + name = obj.vertex_groups[bone_array[index][0]].name + for bone_index, bone in enumerate(armature.pose.bones): + if bone.name != name: continue if array_index is 0: entry = bone_map.get(bone_index, -1) @@ -665,254 +818,102 @@ def _skinning_data(mesh, bone_map, influences, array_index): return manifest -def _skeletal_animations(armature, options): - action = armature.animation_data.action - end_frame = action.frame_range[1] - start_frame = action.frame_range[0] - frame_length = end_frame - start_frame - l,r,s = armature.matrix_world.decompose() - rotation_matrix = r.to_matrix() - hierarchy = [] - parent_index = -1 - frame_step = options.get(constants.FRAME_STEP, 1) - fps = context.scene.render.fps - - start = int(start_frame) - end = int(end_frame / frame_step) + 1 - - #@TODO need key constants - for bone in armature.data.bones: - if bone.use_deform is False: - logger.info('Skipping animation data for bone %s', bone.name) - continue - - logger.info('Parsing animation data for bone %s', bone.name) - - keys = [] - for frame in range(start, end): - computed_frame = frame * frame_step - pos, pchange = _position(bone, computed_frame, - action, armature.matrix_world) - rot, rchange = _rotation(bone, computed_frame, - action, rotation_matrix) - - # flip y and z - px, py, pz = pos.x, pos.z, -pos.y - rx, ry, rz, rw = rot.x, rot.z, -rot.y, rot.w - - if frame == start_frame: - - time = (frame * frame_step - start_frame) / fps - keyframe = { - 'time': time, - 'pos': [px, py, pz], - 'rot': [rx, ry, rz, rw], - 'scl': [1, 1, 1] - } - keys.append(keyframe) - - # END-FRAME: needs pos, rot and scl attributes - # with animation length (required frame) - - elif frame == end_frame / frame_step: - - time = frame_length / fps - keyframe = { - 'time': time, - 'pos': [px, py, pz], - 'rot': [rx, ry, rz, rw], - 'scl': [1, 1, 1] - } - keys.append(keyframe) - - # MIDDLE-FRAME: needs only one of the attributes, - # can be an empty frame (optional frame) - - elif pchange == True or rchange == True: - - time = (frame * frame_step - start_frame) / fps - - if pchange == True and rchange == True: - keyframe = { - 'time': time, - 'pos': [px, py, pz], - 'rot': [rx, ry, rz, rw] - } - elif pchange == True: - keyframe = { - 'time': time, - 'pos': [px, py, pz] - } - elif rchange == True: - keyframe = { - 'time': time, - 'rot': [rx, ry, rz, rw] - } - - keys.append(keyframe) - - hierarchy.append({'keys': keys, 'parent': parent_index}) - parent_index += 1 - - #@TODO key constants - animation = { - 'hierarchy': hierarchy, - 'length':frame_length / fps, - 'fps': fps, - 'name': action.name - } - - return animation - - -def _position(bone, frame, action, armature_matrix): - - position = mathutils.Vector((0,0,0)) - change = False - - ngroups = len(action.groups) - - if ngroups > 0: - - index = 0 - - for i in range(ngroups): - if action.groups[i].name == bone.name: - index = i - - for channel in action.groups[index].channels: - if "location" in channel.data_path: - has_changed = _handle_position_channel( - channel, frame, position) - change = change or has_changed - - else: - - bone_label = '"%s"' % bone.name - - for channel in action.fcurves: - data_path = channel.data_path - if bone_label in data_path and \ - "location" in data_path: - has_changed = _handle_position_channel( - channel, frame, position) - change = change or has_changed - - position = position * bone.matrix_local.inverted() - - if bone.parent is None: - - position.x += bone.head.x - position.y += bone.head.y - position.z += bone.head.z - - else: - - parent = bone.parent - - parent_matrix = parent.matrix_local.inverted() - diff = parent.tail_local - parent.head_local - - position.x += (bone.head * parent_matrix).x + diff.x - position.y += (bone.head * parent_matrix).y + diff.y - position.z += (bone.head * parent_matrix).z + diff.z +def _pose_bones(armature): + """ - return armature_matrix*position, change + :param armature: + :rtype: [], {} + """ + bones_ = [] + bone_map = {} + bone_count = 0 -def _rotation(bone, frame, action, armature_matrix): - - # TODO: calculate rotation also from rotation_euler channels - - rotation = mathutils.Vector((0,0,0,1)) - - change = False - - ngroups = len(action.groups) - - # animation grouped by bones - - if ngroups > 0: - - index = -1 - - for i in range(ngroups): - if action.groups[i].name == bone.name: - index = i - - if index > -1: - for channel in action.groups[index].channels: - if "quaternion" in channel.data_path: - has_changed = _handle_rotation_channel( - channel, frame, rotation) - change = change or has_changed - - # animation in raw fcurves - - else: - - bone_label = '"%s"' % bone.name - - for channel in action.fcurves: - data_path = channel.data_path - if bone_label in data_path and \ - "quaternion" in data_path: - has_changed = _handle_rotation_channel( - channel, frame, rotation) - change = change or has_changed - - rot3 = rotation.to_3d() - rotation.xyz = rot3 * bone.matrix_local.inverted() - rotation.xyz = armature_matrix * rotation.xyz - - return rotation, change - - -def _handle_rotation_channel(channel, frame, rotation): - - change = False - - if channel.array_index in [0, 1, 2, 3]: - - for keyframe in channel.keyframe_points: - if keyframe.co[0] == frame: - change = True + armature_matrix = armature.matrix_world + for bone_count, pose_bone in enumerate(armature.pose.bones): + armature_bone = pose_bone.bone + bone_index = None - value = channel.evaluate(frame) + if armature_bone.parent is None: + bone_matrix = armature_matrix * armature_bone.matrix_local + bone_index = -1 + else: + parent_bone = armature_bone.parent + parent_matrix = armature_matrix * parent_bone.matrix_local + bone_matrix = armature_matrix * armature_bone.matrix_local + bone_matrix = parent_matrix.inverted() * bone_matrix + bone_index = index = 0 + + for pose_parent in armature.pose.bones: + armature_parent = pose_parent.bone.name + if armature_parent == parent_bone.name: + bone_index = index + index += 1 - if channel.array_index == 1: - rotation.x = value + bone_map[bone_count] = bone_count - elif channel.array_index == 2: - rotation.y = value + pos, rot, scl = bone_matrix.decompose() + bones_.append({ + constants.PARENT: bone_index, + constants.NAME: armature_bone.name, + constants.POS: (pos.x, pos.z, -pos.y), + constants.ROTQ: (rot.x, rot.z, -rot.y, rot.w), + constants.SCL: (scl.x, scl.z, scl.y) + }) - elif channel.array_index == 3: - rotation.z = value + return bones_, bone_map - elif channel.array_index == 0: - rotation.w = value - return change +def _rest_bones(armature): + """ + :param armature: + :rtype: [], {} -def _handle_position_channel(channel, frame, position): + """ + bones_ = [] + bone_map = {} + bone_count = 0 + bone_index_rel = 0 - change = False + for bone in armature.data.bones: + logger.info("Parsing bone %s", bone.name) - if channel.array_index in [0, 1, 2]: - for keyframe in channel.keyframe_points: - if keyframe.co[0] == frame: - change = True + if not bone.use_deform: + logger.debug("Ignoring bone %s at: %d", + bone.name, bone_index_rel) + continue - value = channel.evaluate(frame) + if bone.parent is None: + bone_pos = bone.head_local + bone_index = -1 + else: + bone_pos = bone.head_local - bone.parent.head_local + bone_index = 0 + index = 0 + for parent in armature.data.bones: + if parent.name == bone.parent.name: + bone_index = bone_map.get(index) + index += 1 - if channel.array_index == 0: - position.x = value + bone_world_pos = armature.matrix_world * bone_pos + x_axis = bone_world_pos.x + y_axis = bone_world_pos.z + z_axis = -bone_world_pos.y - if channel.array_index == 1: - position.y = value + logger.debug("Adding bone %s at: %s, %s", + bone.name, bone_index, bone_index_rel) + bone_map[bone_count] = bone_index_rel + bone_index_rel += 1 + # @TODO: the rotq probably should not have these + # hard coded values + bones_.append({ + constants.PARENT: bone_index, + constants.NAME: bone.name, + constants.POS: (x_axis, y_axis, z_axis), + constants.ROTQ: (0, 0, 0, 1) + }) - if channel.array_index == 2: - position.z = value + bone_count += 1 - return change + return (bones_, bone_map) diff --git a/utils/exporters/blender/addons/io_three/exporter/api/object.py b/utils/exporters/blender/addons/io_three/exporter/api/object.py index 4c4716e58095ee..2e6c0cd5639516 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/object.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/object.py @@ -2,6 +2,7 @@ import mathutils import bpy from bpy import data, context, types +from bpy_extras.io_utils import axis_conversion from .. import constants, logger, utilities, exceptions from .constants import ( MESH, @@ -17,13 +18,10 @@ PERSP, ORTHO, RENDER, - ZYX, - NO_SHADOW + NO_SHADOW, + ZYX ) -ROTATE_X_PI2 = mathutils.Quaternion((1.0, 0.0, 0.0), - math.radians(-90.0)).to_matrix().to_4x4() - # Blender doesn't seem to have a good way to link a mesh back to the # objects that are instancing it, or it is bloody obvious and I haven't @@ -33,32 +31,62 @@ def _object(func): + """ + + :param func: + + """ - def inner(name, *args, **kwargs): + def inner(arg, *args, **kwargs): + """ - if isinstance(name, types.Object): - obj = name + :param arg: + :param *args: + :param **kwargs: + + """ + + if isinstance(arg, types.Object): + obj = arg else: - obj = data.objects[name] + obj = data.objects[arg] return func(obj, *args, **kwargs) return inner -def assemblies(valid_types): +def clear_mesh_map(): + """Clears the mesh map, required on initialization""" + _MESH_MAP.clear() + + +def assemblies(valid_types, options): + """ + + :param valid_types: + :param options: + + """ logger.debug('object.assemblies(%s)', valid_types) for obj in data.objects: - if not obj.parent and obj.type in valid_types: - yield obj.name - elif obj.parent and not obj.parent.parent \ - and obj.parent.type == ARMATURE: + + # rigged assets are parented under armature nodes + if obj.parent and obj.parent.type != ARMATURE: + continue + if obj.parent and obj.parent.type == ARMATURE: logger.info('Has armature parent %s', obj.name) + if _valid_node(obj, valid_types, options): yield obj.name @_object def cast_shadow(obj): + """ + + :param obj: + + """ logger.debug('object.cast_shadow(%s)', obj) if obj.type == LAMP: if obj.data.type in (SPOT, SUN): @@ -78,6 +106,12 @@ def cast_shadow(obj): @_object def children(obj, valid_types): + """ + + :param obj: + :param valid_types: + + """ logger.debug('object.children(%s, %s)', obj, valid_types) for child in obj.children: if child.type in valid_types: @@ -86,6 +120,11 @@ def children(obj, valid_types): @_object def material(obj): + """ + + :param obj: + + """ logger.debug('object.material(%s)', obj) try: return obj.material_slots[0].name @@ -95,38 +134,54 @@ def material(obj): @_object def mesh(obj, options): + """ + + :param obj: + :param options: + + """ logger.debug('object.mesh(%s, %s)', obj, options) if obj.type != MESH: return - - for mesh, objects in _MESH_MAP.items(): + + for mesh_, objects in _MESH_MAP.items(): if obj in objects: - return mesh + return mesh_ else: logger.debug('Could not map object, updating manifest') - mesh = extract_mesh(obj, options) - if len(mesh.tessfaces) is not 0: - manifest = _MESH_MAP.setdefault(mesh.name, []) + mesh_ = extract_mesh(obj, options) + if len(mesh_.tessfaces) is not 0: + manifest = _MESH_MAP.setdefault(mesh_.name, []) manifest.append(obj) - mesh = mesh.name + mesh_name = mesh_.name else: # possibly just being used as a controller logger.info('Object %s has no faces', obj.name) - mesh = None + mesh_name = None - return mesh + return mesh_name @_object def name(obj): + """ + + :param obj: + + """ return obj.name @_object def node_type(obj): + """ + + :param obj: + + """ logger.debug('object.node_type(%s)', obj) # standard transformation nodes are inferred - if obj.type == MESH: + if obj.type == MESH: return constants.MESH.title() elif obj.type == EMPTY: return constants.OBJECT.title() @@ -149,52 +204,39 @@ def node_type(obj): except AttributeError: msg = 'Invalid type: %s' % obj.type raise exceptions.UnsupportedObjectType(msg) - -def nodes(valid_types, options): - visible_layers = _visible_scene_layers() - for obj in data.objects: - # skip objects that are not on visible layers - if not _on_visible_layer(obj, visible_layers): - continue - try: - export = obj.THREE_export - except AttributeError: - export = True - mesh_node = mesh(obj, options) - is_mesh = obj.type == MESH - - # skip objects that a mesh could not be resolved - if is_mesh and not mesh_node: - continue +def nodes(valid_types, options): + """ - # secondary test; if a mesh node was resolved but no - # faces are detected then bow out - if is_mesh: - mesh_node = data.meshes[mesh_node] - if len(mesh_node.tessfaces) is 0: - continue + :param valid_types: + :param options: - if obj.type in valid_types and export: + """ + for obj in data.objects: + if _valid_node(obj, valid_types, options): yield obj.name - @_object def position(obj, options): - logger.debug('object.position(%s)', obj) - vector = _matrix(obj)[0] - vector = (vector.x, vector.y, vector.z) + """ - round_off, round_val = utilities.rounding(options) - if round_off: - vector = utilities.round_off(vector, round_val) + :param obj: + :param options: - return vector + """ + logger.debug('object.position(%s)', obj) + vector = matrix(obj, options).to_translation() + return (vector.x, vector.y, vector.z) @_object def receive_shadow(obj): + """ + + :param obj: + + """ if obj.type == MESH: mat = material(obj) if mat: @@ -203,84 +245,126 @@ def receive_shadow(obj): return False +AXIS_CONVERSION = axis_conversion(to_forward='Z', to_up='Y').to_4x4() + +@_object +def matrix(obj, options): + """ + + :param obj: + :param options: + + """ + logger.debug('object.matrix(%s)', obj) + if options.get(constants.HIERARCHY, False) and obj.parent: + parent_inverted = obj.parent.matrix_world.inverted(mathutils.Matrix()) + return parent_inverted * obj.matrix_world + else: + return AXIS_CONVERSION * obj.matrix_world + + @_object def rotation(obj, options): - logger.debug('object.rotation(%s)', obj) - vector = _matrix(obj)[1].to_euler(ZYX) - vector = (vector.x, vector.y, vector.z) + """ - round_off, round_val = utilities.rounding(options) - if round_off: - vector = utilities.round_off(vector, round_val) + :param obj: + :param options: - return vector + """ + logger.debug('object.rotation(%s)', obj) + vector = matrix(obj, options).to_euler(ZYX) + return (vector.x, vector.y, vector.z) @_object def scale(obj, options): - logger.debug('object.scale(%s)', obj) - vector = _matrix(obj)[2] - vector = (vector.x, vector.y, vector.z) + """ - round_off, round_val = utilities.rounding(options) - if round_off: - vector = utilities.round_off(vector, round_val) + :param obj: + :param options: - return vector + """ + logger.debug('object.scale(%s)', obj) + vector = matrix(obj, options).to_scale() + return (vector.x, vector.y, vector.z) @_object def select(obj): + """ + + :param obj: + + """ obj.select = True @_object def unselect(obj): + """ + + :param obj: + + """ obj.select = False @_object def visible(obj): + """ + + :param obj: + + """ logger.debug('object.visible(%s)', obj) return obj.is_visible(context.scene) def extract_mesh(obj, options, recalculate=False): + """ + + :param obj: + :param options: + :param recalculate: (Default value = False) + + """ logger.debug('object.extract_mesh(%s, %s)', obj, options) - mesh = obj.to_mesh(context.scene, True, RENDER) + mesh_node = obj.to_mesh(context.scene, True, RENDER) # transfer the geometry type to the extracted mesh - mesh.THREE_geometry_type = obj.data.THREE_geometry_type + mesh_node.THREE_geometry_type = obj.data.THREE_geometry_type # now determine whether or not to export using the geometry type # set globally from the exporter's options or to use the local # override on the mesh node itself - opt_buffer = options.get(constants.GEOMETRY_TYPE) + opt_buffer = options.get(constants.GEOMETRY_TYPE) opt_buffer = opt_buffer == constants.BUFFER_GEOMETRY - prop_buffer = mesh.THREE_geometry_type == constants.BUFFER_GEOMETRY + prop_buffer = mesh_node.THREE_geometry_type == constants.BUFFER_GEOMETRY # if doing buffer geometry it is imperative to triangulate the mesh if opt_buffer or prop_buffer: original_mesh = obj.data - obj.data = mesh - logger.debug('swapped %s for %s', original_mesh.name, mesh.name) - + obj.data = mesh_node + logger.debug('swapped %s for %s', + original_mesh.name, + mesh_node.name) + obj.select = True bpy.context.scene.objects.active = obj logger.info('Applying triangulation to %s', obj.data.name) bpy.ops.object.modifier_add(type='TRIANGULATE') - bpy.ops.object.modifier_apply(apply_as='DATA', - modifier='Triangulate') + bpy.ops.object.modifier_apply(apply_as='DATA', + modifier='Triangulate') obj.data = original_mesh obj.select = False # recalculate the normals to face outwards, this is usually - # best after applying a modifiers, especialy for something + # best after applying a modifiers, especialy for something # like the mirror if recalculate: logger.info('Recalculating normals') original_mesh = obj.data - obj.data = mesh + obj.data = mesh_node bpy.context.scene.objects.active = obj bpy.ops.object.mode_set(mode='EDIT') @@ -292,64 +376,72 @@ def extract_mesh(obj, options, recalculate=False): if not options.get(constants.SCENE): xrot = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X') - mesh.transform(xrot * obj.matrix_world) + mesh_node.transform(xrot * obj.matrix_world) # now generate a unique name index = 0 while True: if index is 0: - name = '%sGeometry' % obj.data.name + mesh_name = '%sGeometry' % obj.data.name else: - name = '%sGeometry.%d' % (obj.data.name, index) + mesh_name = '%sGeometry.%d' % (obj.data.name, index) try: - data.meshes[name] + data.meshes[mesh_name] index += 1 except KeyError: break - mesh.name = name + mesh_node.name = mesh_name + + mesh_node.update(calc_tessface=True) + mesh_node.calc_normals() + mesh_node.calc_tessface() + scale_ = options.get(constants.SCALE, 1) + mesh_node.transform(mathutils.Matrix.Scale(scale_, 4)) - mesh.update(calc_tessface=True) - mesh.calc_normals() - mesh.calc_tessface() - scale = options.get(constants.SCALE, 1) - mesh.transform(mathutils.Matrix.Scale(scale, 4)) + return mesh_node - return mesh +def objects_using_mesh(mesh_node): + """ -def objects_using_mesh(mesh): - logger.debug('object.objects_using_mesh(%s)', mesh) - for name, objects in _MESH_MAP.items(): - if name == mesh.name: + :param mesh_node: + :return: list of object names + + """ + logger.debug('object.objects_using_mesh(%s)', mesh_node) + for mesh_name, objects in _MESH_MAP.items(): + if mesh_name == mesh_node.name: return objects else: logger.warning('Could not find mesh mapping') def prep_meshes(options): - ''' - Prep the mesh nodes. Preperation includes identifying: + """Prep the mesh nodes. Preperation includes identifying: - nodes that are on visible layers - nodes that have export disabled - nodes that have modifiers that need to be applied - ''' + + :param options: + + """ logger.debug('object.prep_meshes(%s)', options) mapping = {} visible_layers = _visible_scene_layers() - + for obj in data.objects: - if obj.type != MESH: + if obj.type != MESH: continue # this is ideal for skipping controller or proxy nodes # that may apply to a Blender but not a 3js scene - if not _on_visible_layer(obj, visible_layers): + if not _on_visible_layer(obj, visible_layers): logger.info('%s is not on a visible layer', obj.name) continue # if someone really insists on a visible node not being exportable - if not obj.THREE_export: + if not obj.THREE_export: logger.info('%s export is disabled', obj.name) continue @@ -360,44 +452,103 @@ def prep_meshes(options): # the mesh making the mesh unique to this particular object if len(obj.modifiers): logger.info('%s has modifiers' % obj.name) - mesh = extract_mesh(obj, options, recalculate=True) - _MESH_MAP[mesh.name] = [obj] + mesh_node = extract_mesh(obj, options, recalculate=True) + _MESH_MAP[mesh_node.name] = [obj] continue - logger.info('adding mesh %s.%s to prep', - obj.name, obj.data.name) + logger.info('adding mesh %s.%s to prep', + obj.name, obj.data.name) manifest = mapping.setdefault(obj.data.name, []) manifest.append(obj) - + # now associate the extracted mesh node with all the objects # that are instancing it for objects in mapping.values(): - mesh = extract_mesh(objects[0], options) - _MESH_MAP[mesh.name] = objects + mesh_node = extract_mesh(objects[0], options) + _MESH_MAP[mesh_node.name] = objects def extracted_meshes(): + """ + + :return: names of extracted mesh nodes + + """ logger.debug('object.extracted_meshes()') return [key for key in _MESH_MAP.keys()] -def _matrix(obj): - matrix = ROTATE_X_PI2 * obj.matrix_world - return matrix.decompose() +def _on_visible_layer(obj, visible_layers): + """ + :param obj: + :param visible_layers: -def _on_visible_layer(obj, visible_layers): - visible = True + """ + is_visible = False for index, layer in enumerate(obj.layers): - if layer and index not in visible_layers: - logger.info('%s is on a hidden layer', obj.name) - visible = False + if layer and index in visible_layers: + is_visible = True break - return visible + + if not is_visible: + logger.info('%s is on a hidden layer', obj.name) + + return is_visible def _visible_scene_layers(): + """ + + :return: list of visiible layer indices + + """ visible_layers = [] for index, layer in enumerate(context.scene.layers): - if layer: visible_layers.append(index) + if layer: + visible_layers.append(index) return visible_layers + + +def _valid_node(obj, valid_types, options): + """ + + :param obj: + :param valid_types: + :param options: + + """ + if obj.type not in valid_types: + return False + + # skip objects that are not on visible layers + visible_layers = _visible_scene_layers() + if not _on_visible_layer(obj, visible_layers): + return False + + try: + export = obj.THREE_export + except AttributeError: + export = True + if not export: + return False + + mesh_node = mesh(obj, options) + is_mesh = obj.type == MESH + + # skip objects that a mesh could not be resolved + if is_mesh and not mesh_node: + return False + + # secondary test; if a mesh node was resolved but no + # faces are detected then bow out + if is_mesh: + mesh_node = data.meshes[mesh_node] + if len(mesh_node.tessfaces) is 0: + return False + + # if we get this far assume that the mesh is valid + return True + + + diff --git a/utils/exporters/blender/addons/io_three/exporter/api/texture.py b/utils/exporters/blender/addons/io_three/exporter/api/texture.py index 4f719fe892883b..33088e9127a794 100644 --- a/utils/exporters/blender/addons/io_three/exporter/api/texture.py +++ b/utils/exporters/blender/addons/io_three/exporter/api/texture.py @@ -5,13 +5,25 @@ def _texture(func): + """ + + :param func: + + """ def inner(name, *args, **kwargs): + """ + + :param name: + :param *args: + :param **kwargs: + + """ if isinstance(name, types.Texture): texture = name else: - texture = data.textures[name] + texture = data.textures[name] return func(texture, *args, **kwargs) @@ -20,37 +32,67 @@ def inner(name, *args, **kwargs): @_texture def anisotropy(texture): - logger.debug('texture.file_path(%s)', texture) + """ + + :param texture: + :return: filter_size value + + """ + logger.debug("texture.file_path(%s)", texture) return texture.filter_size @_texture def file_name(texture): - logger.debug('texture.file_name(%s)', texture) + """ + + :param texture: + :return: file name + + """ + logger.debug("texture.file_name(%s)", texture) if texture.image: return image.file_name(texture.image) @_texture def file_path(texture): - logger.debug('texture.file_path(%s)', texture) + """ + + :param texture: + :return: file path + + """ + logger.debug("texture.file_path(%s)", texture) if texture.image: return image.file_path(texture.image) @_texture def image_node(texture): - logger.debug('texture.image_node(%s)', texture) + """ + + :param texture: + :return: texture's image node + + """ + logger.debug("texture.image_node(%s)", texture) return texture.image @_texture def mag_filter(texture): - logger.debug('texture.mag_filter(%s)', texture) + """ + + :param texture: + :return: THREE_mag_filter value + + """ + logger.debug("texture.mag_filter(%s)", texture) try: val = texture.THREE_mag_filter except AttributeError: - logger.debug('No THREE_mag_filter attribute found') + logger.debug("No THREE_mag_filter attribute found") val = MAG_FILTER return val @@ -58,44 +100,79 @@ def mag_filter(texture): @_texture def mapping(texture): - logger.debug('texture.mapping(%s)', texture) + """ + + :param texture: + :return: THREE_mapping value + + """ + logger.debug("texture.mapping(%s)", texture) try: val = texture.THREE_mapping except AttributeError: - logger.debug('No THREE_mapping attribute found') + logger.debug("No THREE_mapping attribute found") val = MAPPING return val + + @_texture def min_filter(texture): - logger.debug('texture.min_filter(%s)', texture) + """ + + :param texture: + :return: THREE_min_filter value + + """ + logger.debug("texture.min_filter(%s)", texture) try: val = texture.THREE_min_filter except AttributeError: - logger.debug('No THREE_min_filter attribute found') - val = MIN_FILTER + logger.debug("No THREE_min_filter attribute found") + val = MIN_FILTER return val @_texture def repeat(texture): - logger.debug('texture.repeat(%s)', texture) + """The repeat parameters of the texture node + + :param texture: + :returns: repeat_x, and repeat_y values + + """ + logger.debug("texture.repeat(%s)", texture) return (texture.repeat_x, texture.repeat_y) @_texture def wrap(texture): - logger.debug('texture.wrap(%s)', texture) + """The wrapping parameters of the texture node + + :param texture: + :returns: tuple of THREE compatible wrapping values + + """ + logger.debug("texture.wrap(%s)", texture) wrapping = { - True: constants.WRAPPING.MIRROR, + True: constants.WRAPPING.MIRROR, False: constants.WRAPPING.REPEAT } - return (wrapping[texture.use_mirror_x], wrapping[texture.use_mirror_y]) + return (wrapping[texture.use_mirror_x], + wrapping[texture.use_mirror_y]) def textures(): - logger.debug('texture.textures()') - for texture in data.textures: - if texture.type == IMAGE: - yield texture.name + """ + + :return: list of texture node names that are IMAGE + + """ + logger.debug("texture.textures()") + for mat in data.materials: + if mat.users == 0: + continue + for slot in mat.texture_slots: + if slot and slot.use and slot.texture.type == IMAGE: + yield slot.texture.name diff --git a/utils/exporters/blender/addons/io_three/exporter/base_classes.py b/utils/exporters/blender/addons/io_three/exporter/base_classes.py index 984785d7f3842a..4953f3b2094c40 100644 --- a/utils/exporters/blender/addons/io_three/exporter/base_classes.py +++ b/utils/exporters/blender/addons/io_three/exporter/base_classes.py @@ -1,40 +1,68 @@ -import uuid -from .. import constants, exceptions +from . import utilities +from .. import constants, exceptions class BaseClass(constants.BASE_DICT): + """Base class which inherits from a base dictionary object.""" _defaults = {} def __init__(self, parent=None, type=None): constants.BASE_DICT.__init__(self) - self.__type = type + self._type = type - self.__parent = parent + self._parent = parent constants.BASE_DICT.update(self, self._defaults.copy()) - + def __setitem__(self, key, value): if not isinstance(value, constants.VALID_DATA_TYPES): - msg = 'Value is an invalid data type: %s' % type(value) - raise exceptions.ThreeValueError(msg) + msg = "Value is an invalid data type: %s" % type(value) + raise exceptions.ThreeValueError(msg) constants.BASE_DICT.__setitem__(self, key, value) @property def count(self): + """ + + :return: number of keys + :rtype: int + + """ return len(self.keys()) @property def parent(self): - return self.__parent + """ + + :return: parent object + + """ + return self._parent @property def type(self): - return self.__type - + """ + + :return: the type (if applicable) + + """ + return self._type + def copy(self): + """Copies the items to a standard dictionary object. + + :rtype: dict + + """ data = {} def _dict_copy(old, new): + """Recursive function for processing all values + + :param old: + :param new: + + """ for key, value in old.items(): if isinstance(value, (str, list)): new[key] = value[:] @@ -51,12 +79,16 @@ def _dict_copy(old, new): return data -class BaseNode(BaseClass): +class BaseNode(BaseClass): + """Base class for all nodes for the current platform.""" def __init__(self, node, parent, type): BaseClass.__init__(self, parent=parent, type=type) - self.__node = node - if node is not None: + self._node = node + if node is None: + self[constants.UUID] = utilities.id() + else: self[constants.NAME] = node + self[constants.UUID] = utilities.id_from_name(node) if isinstance(parent, BaseScene): scene = parent @@ -65,35 +97,51 @@ def __init__(self, node, parent, type): else: scene = None - self.__scene = scene + self._scene = scene - self[constants.UUID] = str(uuid.uuid4()).upper() - @property def node(self): - return self.__node + """ + + :return: name of the node + + """ + return self._node @property def scene(self): - return self.__scene + """ + + :return: returns the scene point + + """ + + return self._scene @property def options(self): + """ + + :return: export options + :retype: dict + + """ return self.scene.options class BaseScene(BaseClass): + """Base class that scenes inherit from.""" def __init__(self, filepath, options): BaseClass.__init__(self, type=constants.SCENE) - self.__filepath = filepath + self._filepath = filepath - self.__options = options.copy() + self._options = options.copy() @property def filepath(self): - return self.__filepath + return self._filepath @property def options(self): - return self.__options + return self._options diff --git a/utils/exporters/blender/addons/io_three/exporter/geometry.py b/utils/exporters/blender/addons/io_three/exporter/geometry.py index 563cdf1973ff96..c44d56c6873efe 100644 --- a/utils/exporters/blender/addons/io_three/exporter/geometry.py +++ b/utils/exporters/blender/addons/io_three/exporter/geometry.py @@ -1,3 +1,7 @@ +""" +Module for creating Three.js geometry JSON nodes. +""" + import os from .. import constants, logger from . import base_classes, io, api @@ -7,9 +11,10 @@ class Geometry(base_classes.BaseNode): + """Class that wraps a single mesh/geometry node.""" def __init__(self, node, parent=None): - logger.debug('Geometry().__init__(%s)', node) - + logger.debug("Geometry().__init__(%s)", node) + #@TODO: maybe better to have `three` constants for # strings that are specific to `three` properties geo_type = constants.GEOMETRY.title() @@ -18,51 +23,58 @@ def __init__(self, node, parent=None): if opt_type == constants.BUFFER_GEOMETRY: geo_type = constants.BUFFER_GEOMETRY elif opt_type != constants.GEOMETRY: - logger.error('Unknown geometry type %s', opt_type) + logger.error("Unknown geometry type %s", opt_type) - logger.info('Setting %s to "%s"', node, geo_type) + logger.info("Setting %s to '%s'", node, geo_type) self._defaults[constants.TYPE] = geo_type - base_classes.BaseNode.__init__(self, node, - parent=parent, - type=geo_type) + base_classes.BaseNode.__init__(self, node, + parent=parent, + type=geo_type) @property def animation_filename(self): + """Calculate the file name for the animation file + + :return: base name for the file + """ compression = self.options.get(constants.COMPRESSION) if compression in (None, constants.NONE): ext = constants.JSON elif compression == constants.MSGPACK: ext = constants.PACK + key = '' for key in (constants.MORPH_TARGETS, constants.ANIMATION): - try: - self[key] + if key in self.keys(): break - except KeyError: - pass else: - logger.info('%s has no animation data', self.node) + logger.info("%s has no animation data", self.node) return return '%s.%s.%s' % (self.node, key, ext) @property def face_count(self): + """Parse the bit masks of the `faces` array. + + :rtype: int + + """ try: faces = self[constants.FACES] except KeyError: - logger.debug('No parsed faces found') + logger.debug("No parsed faces found") return 0 length = len(faces) offset = 0 - bitset = lambda x,y: x & ( 1 << y ) + bitset = lambda x, y: x & (1 << y) face_count = 0 masks = (constants.MASK[constants.UVS], - constants.MASK[constants.NORMALS], - constants.MASK[constants.COLORS]) + constants.MASK[constants.NORMALS], + constants.MASK[constants.COLORS]) while offset < length: bit = faces[offset] @@ -84,20 +96,33 @@ def face_count(self): @property def metadata(self): + """Metadata for the current node. + + :rtype: dict + + """ metadata = { constants.GENERATOR: constants.THREE, constants.VERSION: FORMAT_VERSION } if self[constants.TYPE] == constants.GEOMETRY.title(): - self.__geometry_metadata(metadata) + self._geometry_metadata(metadata) else: - self.__buffer_geometry_metadata(metadata) + self._buffer_geometry_metadata(metadata) return metadata def copy(self, scene=True): - logger.debug('Geometry().copy(scene=%s)', scene) + """Copy the geometry definitions to a standard dictionary. + + :param scene: toggle for scene formatting + (Default value = True) + :type scene: bool + :rtype: dict + + """ + logger.debug("Geometry().copy(scene=%s)", scene) dispatch = { True: self._scene_format, False: self._geometry_format @@ -107,47 +132,70 @@ def copy(self, scene=True): try: data[constants.MATERIALS] = self[constants.MATERIALS].copy() except KeyError: - logger.debug('No materials to copy') + logger.debug("No materials to copy") return data - def copy_textures(self): - logger.debug('Geometry().copy_textures()') + def copy_textures(self, texture_folder=''): + """Copy the textures to the destination directory.""" + logger.debug("Geometry().copy_textures()") if self.options.get(constants.COPY_TEXTURES): texture_registration = self.register_textures() if texture_registration: - logger.info('%s has registered textures', self.node) + logger.info("%s has registered textures", self.node) + dirname = os.path.dirname(self.scene.filepath) + full_path = os.path.join(dirname, texture_folder) io.copy_registered_textures( - os.path.dirname(self.scene.filepath), - texture_registration) + full_path, texture_registration) def parse(self): - logger.debug('Geometry().parse()') + """Parse the current node""" + logger.debug("Geometry().parse()") if self[constants.TYPE] == constants.GEOMETRY.title(): - logger.info('Parsing Geometry format') - self.__parse_geometry() + logger.info("Parsing Geometry format") + self._parse_geometry() else: - logger.info('Parsing BufferGeometry format') - self.__parse_buffer_geometry() + logger.info("Parsing BufferGeometry format") + self._parse_buffer_geometry() def register_textures(self): - logger.debug('Geometry().register_textures()') - return api.mesh.texture_registration(self.node) + """Obtain a texture registration object. + + :rtype: dict + + """ + logger.debug("Geometry().register_textures()") + return api.mesh.texture_registration(self.node) def write(self, filepath=None): - logger.debug('Geometry().write(filepath=%s)', filepath) + """Write the geometry definitions to disk. Uses the + desitnation path of the scene. + + :param filepath: optional output file path + (Default value = None) + :type filepath: str + + """ + logger.debug("Geometry().write(filepath=%s)", filepath) filepath = filepath or self.scene.filepath - io.dump(filepath, self.copy(scene=False), - options=self.scene.options) + io.dump(filepath, self.copy(scene=False), + options=self.scene.options) if self.options.get(constants.MAPS): - logger.info('Copying textures for %s', self.node) + logger.info("Copying textures for %s", self.node) self.copy_textures() def write_animation(self, filepath): - logger.debug('Geometry().write_animation(%s)', filepath) + """Write the animation definitions to a separate file + on disk. This helps optimize the geometry file size. + + :param filepath: destination path + :type filepath: str + + """ + logger.debug("Geometry().write_animation(%s)", filepath) for key in (constants.MORPH_TARGETS, constants.ANIMATION): try: @@ -156,29 +204,35 @@ def write_animation(self, filepath): except KeyError: pass else: - logger.info('%s has no animation data', self.node) + logger.info("%s has no animation data", self.node) return filepath = os.path.join(filepath, self.animation_filename) if filepath: - logger.info('Dumping animation data to %s', filepath) + logger.info("Dumping animation data to %s", filepath) io.dump(filepath, data, options=self.scene.options) return filepath else: - logger.warning('Could not determine a filepath for '\ - 'animation data. Nothing written to disk.') + logger.warning("Could not determine a filepath for "\ + "animation data. Nothing written to disk.") def _component_data(self): - logger.debug('Geometry()._component_data()') - + """Query the component data only + + :rtype: dict + + """ + logger.debug("Geometry()._component_data()") + if self[constants.TYPE] != constants.GEOMETRY.title(): return self[constants.ATTRIBUTES] - components = [constants.VERTICES, constants.FACES, - constants.UVS, constants.COLORS, constants.NORMALS, - constants.BONES, constants.SKIN_WEIGHTS, - constants.SKIN_INDICES, constants.NAME, - constants.INFLUENCES_PER_VERTEX] + components = [constants.VERTICES, constants.FACES, + constants.UVS, constants.COLORS, + constants.NORMALS, constants.BONES, + constants.SKIN_WEIGHTS, + constants.SKIN_INDICES, constants.NAME, + constants.INFLUENCES_PER_VERTEX] data = {} anim_components = [constants.MORPH_TARGETS, constants.ANIMATION] @@ -192,20 +246,25 @@ def _component_data(self): pass else: data[component] = os.path.basename( - self.animation_filename) + self.animation_filename) + break else: - logger.info('No animation data found for %s', self.node) + logger.info("No animation data found for %s", self.node) for component in components: try: data[component] = self[component] except KeyError: - logger.debug('Component %s not found', component) - pass + logger.debug("Component %s not found", component) return data def _geometry_format(self): + """Three.Geometry formatted definitions + + :rtype: dict + + """ data = self._component_data() if self[constants.TYPE] != constants.GEOMETRY.title(): @@ -219,17 +278,27 @@ def _geometry_format(self): return data - def __buffer_geometry_metadata(self, metadata): + def _buffer_geometry_metadata(self, metadata): + """Three.BufferGeometry metadata + + :rtype: dict + + """ for key, value in self[constants.ATTRIBUTES].items(): size = value[constants.ITEM_SIZE] array = value[constants.ARRAY] metadata[key] = len(array)/size - - def __geometry_metadata(self, metadata): + + def _geometry_metadata(self, metadata): + """Three.Geometry metadat + + :rtype: dict + + """ skip = (constants.TYPE, constants.FACES, constants.UUID, - constants.ANIMATION, constants.SKIN_INDICES, - constants.SKIN_WEIGHTS, constants.NAME, - constants.INFLUENCES_PER_VERTEX) + constants.ANIMATION, constants.SKIN_INDICES, + constants.SKIN_WEIGHTS, constants.NAME, + constants.INFLUENCES_PER_VERTEX) vectors = (constants.VERTICES, constants.NORMALS) for key in self.keys(): @@ -240,7 +309,8 @@ def __geometry_metadata(self, metadata): pass continue - if key in skip: continue + if key in skip: + continue metadata[key] = len(self[key]) @@ -249,6 +319,11 @@ def __geometry_metadata(self, metadata): metadata[constants.FACES] = faces def _scene_format(self): + """Format the output for Scene compatability + + :rtype: dict + + """ data = { constants.UUID: self[constants.UUID], constants.TYPE: self[constants.TYPE] @@ -261,40 +336,41 @@ def _scene_format(self): constants.METADATA: self.metadata }) else: - if self.options[constants.EMBED_GEOMETRY]: + if self.options.get(constants.EMBED_GEOMETRY, True): data[constants.DATA] = { constants.ATTRIBUTES: component_data } else: data[constants.ATTRIBUTES] = component_data - data[constants.METADATA] = self.metadata + data[constants.METADATA] = self.metadata data[constants.NAME] = self[constants.NAME] - return data + return data - def __parse_buffer_geometry(self): + def _parse_buffer_geometry(self): + """Parse the geometry to Three.BufferGeometry specs""" self[constants.ATTRIBUTES] = {} options_vertices = self.options.get(constants.VERTICES) option_normals = self.options.get(constants.NORMALS) option_uvs = self.options.get(constants.UVS) - dispatch = ( - (constants.POSITION, options_vertices, - api.mesh.buffer_position, 3), - (constants.UV, option_uvs, api.mesh.buffer_uv, 2), - (constants.NORMAL, option_normals, - api.mesh.buffer_normal, 3) - ) + pos_tuple = (constants.POSITION, options_vertices, + api.mesh.buffer_position, 3) + uvs_tuple = (constants.UV, option_uvs, + api.mesh.buffer_uv, 2) + normals_tuple = (constants.NORMAL, option_normals, + api.mesh.buffer_normal, 3) + dispatch = (pos_tuple, uvs_tuple, normals_tuple) - for key, option, func, size in dispatch: + for key, option, func, size in dispatch: if not option: continue - array = func(self.node, self.options) - if not array: - logger.warning('No array could be made for %s', key) + array = func(self.node) or [] + if not array: + logger.warning("No array could be made for %s", key) continue self[constants.ATTRIBUTES][key] = { @@ -303,64 +379,63 @@ def __parse_buffer_geometry(self): constants.ARRAY: array } - def __parse_geometry(self): + def _parse_geometry(self): + """Parse the geometry to Three.Geometry specs""" if self.options.get(constants.VERTICES): - logger.info('Parsing %s', constants.VERTICES) - self[constants.VERTICES] = api.mesh.vertices( - self.node, self.options) - - if self.options.get(constants.FACES): - logger.info('Parsing %s', constants.FACES) - self[constants.FACES] = api.mesh.faces( - self.node, self.options) + logger.info("Parsing %s", constants.VERTICES) + self[constants.VERTICES] = api.mesh.vertices(self.node) or [] if self.options.get(constants.NORMALS): - logger.info('Parsing %s', constants.NORMALS) - self[constants.NORMALS] = api.mesh.normals( - self.node, self.options) + logger.info("Parsing %s", constants.NORMALS) + self[constants.NORMALS] = api.mesh.normals(self.node) or [] if self.options.get(constants.COLORS): - logger.info('Parsing %s', constants.COLORS) + logger.info("Parsing %s", constants.COLORS) self[constants.COLORS] = api.mesh.vertex_colors( - self.node) - + self.node) or [] + if self.options.get(constants.FACE_MATERIALS): - logger.info('Parsing %s', constants.FACE_MATERIALS) + logger.info("Parsing %s", constants.FACE_MATERIALS) self[constants.MATERIALS] = api.mesh.materials( - self.node, self.options) + self.node, self.options) or [] if self.options.get(constants.UVS): - logger.info('Parsing %s', constants.UVS) - self[constants.UVS] = api.mesh.uvs( - self.node, self.options) + logger.info("Parsing %s", constants.UVS) + self[constants.UVS] = api.mesh.uvs(self.node) or [] + + if self.options.get(constants.FACES): + logger.info("Parsing %s", constants.FACES) + self[constants.FACES] = api.mesh.faces( + self.node, self.options) or [] - if self.options.get(constants.ANIMATION): - logger.info('Parsing %s', constants.ANIMATION) - self[constants.ANIMATION] = api.mesh.animation( - self.node, self.options) + no_anim = (None, False, constants.OFF) + if self.options.get(constants.ANIMATION) not in no_anim: + logger.info("Parsing %s", constants.ANIMATION) + self[constants.ANIMATION] = api.mesh.skeletal_animation( + self.node, self.options) or [] #@TODO: considering making bones data implied when # querying skinning data bone_map = {} if self.options.get(constants.BONES): - logger.info('Parsing %s', constants.BONES) - bones, bone_map = api.mesh.bones(self.node) + logger.info("Parsing %s", constants.BONES) + bones, bone_map = api.mesh.bones(self.node, self.options) self[constants.BONES] = bones if self.options.get(constants.SKINNING): - logger.info('Parsing %s', constants.SKINNING) + logger.info("Parsing %s", constants.SKINNING) influences = self.options.get( constants.INFLUENCES_PER_VERTEX, 2) self[constants.INFLUENCES_PER_VERTEX] = influences self[constants.SKIN_INDICES] = api.mesh.skin_indices( - self.node, bone_map, influences) + self.node, bone_map, influences) or [] self[constants.SKIN_WEIGHTS] = api.mesh.skin_weights( - self.node, bone_map, influences) + self.node, bone_map, influences) or [] if self.options.get(constants.MORPH_TARGETS): - logger.info('Parsing %s', constants.MORPH_TARGETS) + logger.info("Parsing %s", constants.MORPH_TARGETS) self[constants.MORPH_TARGETS] = api.mesh.morph_targets( - self.node, self.options) + self.node, self.options) or [] diff --git a/utils/exporters/blender/addons/io_three/exporter/image.py b/utils/exporters/blender/addons/io_three/exporter/image.py index 64af5c9c31339d..74f7a5b266463f 100644 --- a/utils/exporters/blender/addons/io_three/exporter/image.py +++ b/utils/exporters/blender/addons/io_three/exporter/image.py @@ -4,22 +4,44 @@ class Image(base_classes.BaseNode): + """Class the wraps an image node. This is the node that + represent that actual file on disk. + """ def __init__(self, node, parent): - logger.debug('Image().__init__(%s)', node) + logger.debug("Image().__init__(%s)", node) base_classes.BaseNode.__init__(self, node, parent, constants.IMAGE) - self[constants.URL] = api.image.file_name(self.node) + texture_folder = self.scene.options.get(constants.TEXTURE_FOLDER, "") + self[constants.URL] = os.path.join(texture_folder, api.image.file_name(self.node)) @property def destination(self): + """ + + :return: full destination path (when copied) + + """ dirname = os.path.dirname(self.scene.filepath) return os.path.join(dirname, self[constants.URL]) @property def filepath(self): + """ + + :return: source file path + + """ return api.image.file_path(self.node) def copy_texture(self, func=io.copy): - logger.debug('Image().copy_texture()') + """Copy the texture. + self.filepath > self.destination + + :param func: Optional function override (Default value = io.copy) + arguments are (, ) + :return: path the texture was copied to + + """ + logger.debug("Image().copy_texture()") func(self.filepath, self.destination) return self.destination diff --git a/utils/exporters/blender/addons/io_three/exporter/io.py b/utils/exporters/blender/addons/io_three/exporter/io.py index 749d02c1e1660d..49231aa54f5ad9 100644 --- a/utils/exporters/blender/addons/io_three/exporter/io.py +++ b/utils/exporters/blender/addons/io_three/exporter/io.py @@ -1,33 +1,62 @@ +import os import shutil from .. import constants, logger from . import _json def copy_registered_textures(dest, registration): - logger.debug('io.copy_registered_textures(%s, %s)', dest, registration) + """Copy the registered textures to the destination (root) path + + :param dest: destination directory + :param registration: registered textures + :type dest: str + :type registration: dict + + """ + logger.debug("io.copy_registered_textures(%s, %s)", dest, registration) + os.makedirs(dest, exist_ok=True) for value in registration.values(): copy(value['file_path'], dest) def copy(src, dst): - logger.debug('io.copy(%s, %s)' % (src, dst)) - shutil.copy(src, dst) + """Copy a file to a destination + + :param src: source file + :param dst: destination file/path + + """ + logger.debug("io.copy(%s, %s)" % (src, dst)) + if os.path.isdir(dst): + file_name = os.path.basename(src) + dst = os.path.join(dst, file_name) + + if src != dst: + shutil.copy(src, dst) def dump(filepath, data, options=None): + """Dump the output to disk (JSON, msgpack, etc) + + :param filepath: output file path + :param data: serializable data to write to disk + :param options: (Default value = None) + :type options: dict + + """ options = options or {} - logger.debug('io.dump(%s, data, options=%s)', filepath, options) + logger.debug("io.dump(%s, data, options=%s)", filepath, options) compress = options.get(constants.COMPRESSION, constants.NONE) if compress == constants.MSGPACK: try: import msgpack except ImportError: - logger.error('msgpack module not found') + logger.error("msgpack module not found") raise - logger.info('Dumping to msgpack') - func = lambda x,y: msgpack.dump(x, y) + logger.info("Dumping to msgpack") + func = lambda x, y: msgpack.dump(x, y) mode = 'wb' else: round_off = options.get(constants.ENABLE_PRECISION) @@ -36,28 +65,37 @@ def dump(filepath, data, options=None): else: _json.ROUND = None - logger.info('Dumping to JSON') - func = lambda x,y: _json.json.dump(x, y, indent=4) + indent = options.get(constants.INDENT, True) + indent = 4 if indent else None + logger.info("Dumping to JSON") + func = lambda x, y: _json.json.dump(x, y, indent=indent) mode = 'w' - logger.info('Writing to %s', filepath) + logger.info("Writing to %s", filepath) with open(filepath, mode=mode) as stream: func(data, stream) def load(filepath, options): - logger.debug('io.load(%s, %s)', filepath, options) + """Load the contents of the file path with the correct parser + + :param filepath: input file path + :param options: + :type options: dict + + """ + logger.debug("io.load(%s, %s)", filepath, options) compress = options.get(constants.COMPRESSION, constants.NONE) if compress == constants.MSGPACK: try: import msgpack except ImportError: - logger.error('msgpack module not found') + logger.error("msgpack module not found") raise module = msgpack mode = 'rb' else: - logger.info('Loading JSON') + logger.info("Loading JSON") module = _json.json mode = 'r' diff --git a/utils/exporters/blender/addons/io_three/exporter/material.py b/utils/exporters/blender/addons/io_three/exporter/material.py index 122b410ffc2337..0a289ad6a61620 100644 --- a/utils/exporters/blender/addons/io_three/exporter/material.py +++ b/utils/exporters/blender/addons/io_three/exporter/material.py @@ -3,21 +3,23 @@ class Material(base_classes.BaseNode): + """Class that wraps material nodes""" def __init__(self, node, parent): - logger.debug('Material().__init__(%s)', node) - base_classes.BaseNode.__init__(self, node, parent, - constants.MATERIAL) - - self.__common_attributes() + logger.debug("Material().__init__(%s)", node) + base_classes.BaseNode.__init__(self, node, parent, + constants.MATERIAL) + + self._common_attributes() if self[constants.TYPE] == constants.THREE_PHONG: - self.__phong_attributes() + self._phong_attributes() textures = self.parent.options.get(constants.MAPS) if textures: - self.__update_maps() + self._update_maps() - def __common_attributes(self): - logger.debug('Material().__common_attributes()') + def _common_attributes(self): + """Parse the common material attributes""" + logger.debug('Material()._common_attributes()') dispatch = { constants.PHONG: constants.THREE_PHONG, constants.LAMBERT: constants.THREE_LAMBERT, @@ -26,14 +28,15 @@ def __common_attributes(self): shader_type = api.material.type(self.node) self[constants.TYPE] = dispatch[shader_type] - ambient = api.material.ambient_color(self.node) - self[constants.AMBIENT] = utilities.rgb2int(ambient) - diffuse = api.material.diffuse_color(self.node) self[constants.COLOR] = utilities.rgb2int(diffuse) - - emissive = api.material.emissive_color(self.node) - self[constants.EMISSIVE] = utilities.rgb2int(emissive) + + if self[constants.TYPE] != constants.THREE_BASIC: + ambient = api.material.ambient_color(self.node) + self[constants.AMBIENT] = utilities.rgb2int(ambient) + + emissive = api.material.emissive_color(self.node) + self[constants.EMISSIVE] = utilities.rgb2int(emissive) vertex_color = api.material.use_vertex_colors(self.node) self[constants.VERTEX_COLORS] = vertex_color @@ -44,14 +47,18 @@ def __common_attributes(self): self[constants.DEPTH_WRITE] = api.material.depth_write(self.node) - def __phong_attributes(self): - logger.debug('Material().__phong_attributes()') + def _phong_attributes(self): + """Parse phong specific attributes""" + logger.debug("Material()._phong_attributes()") specular = api.material.specular_color(self.node) self[constants.SPECULAR] = utilities.rgb2int(specular) self[constants.SHININESS] = api.material.specular_coef(self.node) - def __update_maps(self): - logger.debug('Material().__update_maps()') + def _update_maps(self): + """Parses maps/textures and updates the textures array + with any new nodes found. + """ + logger.debug("Material()._update_maps()") mapping = ( (api.material.diffuse_map, constants.MAP), @@ -59,14 +66,14 @@ def __update_maps(self): (api.material.light_map, constants.LIGHT_MAP) ) - for func,key in mapping: + for func, key in mapping: map_node = func(self.node) if map_node: logger.info('Found map node %s for %s', map_node, key) tex_inst = self.scene.texture(map_node.name) - self[key] = tex_inst[constants.UUID] + self[key] = tex_inst[constants.UUID] - if self[constants.TYPE] == constants.THREE_PHONG: + if self[constants.TYPE] == constants.THREE_PHONG: mapping = ( (api.material.bump_map, constants.BUMP_MAP, constants.BUMP_SCALE, api.material.bump_scale), @@ -76,8 +83,9 @@ def __update_maps(self): for func, map_key, scale_key, scale_func in mapping: map_node = func(self.node) - if not map_node: continue - logger.info('Found map node %s for %s', map_node, map_key) + if not map_node: + continue + logger.info("Found map node %s for %s", map_node, map_key) tex_inst = self.scene.texture(map_node.name) - self[map_key] = tex_inst[constants.UUID] + self[map_key] = tex_inst[constants.UUID] self[scale_key] = scale_func(self.node) diff --git a/utils/exporters/blender/addons/io_three/exporter/object.py b/utils/exporters/blender/addons/io_three/exporter/object.py index 1f43024a353574..3da492f540f442 100644 --- a/utils/exporters/blender/addons/io_three/exporter/object.py +++ b/utils/exporters/blender/addons/io_three/exporter/object.py @@ -3,114 +3,131 @@ class Object(base_classes.BaseNode): - + """Class that wraps an object node""" def __init__(self, node, parent=None, type=None): - logger.debug('Object().__init__(%s)', node) + logger.debug("Object().__init__(%s)", node) base_classes.BaseNode.__init__(self, node, parent=parent, type=type) if self.node: - self.__node_setup() + self._node_setup() else: - self.__root_setup() + self._root_setup() + + @property + def data(self): + """ + + :return: returns the data block of the node + + """ + return api.data(self.node) + - def __init_camera(self): - logger.debug('Object().__init_camera()') - self[constants.FAR] = api.camera.far(self.node) - self[constants.NEAR] = api.camera.near(self.node) + def _init_camera(self): + """Initialize camera attributes""" + logger.debug("Object()._init_camera()") + self[constants.FAR] = api.camera.far(self.data) + self[constants.NEAR] = api.camera.near(self.data) if self[constants.TYPE] == constants.PERSPECTIVE_CAMERA: - self[constants.ASPECT] = api.camera.aspect(self.node) - self[constants.FOV] = api.camera.fov(self.node) + self[constants.ASPECT] = api.camera.aspect(self.data) + self[constants.FOV] = api.camera.fov(self.data) elif self[constants.TYPE] == constants.ORTHOGRAPHIC_CAMERA: - self[constants.LEFT] = api.camera.left(self.node) - self[constants.RIGHT] = api.camera.right(self.node) - self[constants.TOP] = api.camera.top(self.node) - self[constants.BOTTOM] = api.camera.bottom(self.node) + self[constants.LEFT] = api.camera.left(self.data) + self[constants.RIGHT] = api.camera.right(self.data) + self[constants.TOP] = api.camera.top(self.data) + self[constants.BOTTOM] = api.camera.bottom(self.data) #@TODO: need more light attributes. Some may have to come from # custom blender attributes. - def __init_light(self): - logger.debug('Object().__init_light()') - self[constants.COLOR] = api.light.color(self.node) - self[constants.INTENSITY] = api.light.intensity(self.node) + def _init_light(self): + """Initialize light attributes""" + logger.debug("Object()._init_light()") + self[constants.COLOR] = api.light.color(self.data) + self[constants.INTENSITY] = api.light.intensity(self.data) if self[constants.TYPE] != constants.DIRECTIONAL_LIGHT: - self[constants.DISTANCE] = api.light.distance(self.node) - + self[constants.DISTANCE] = api.light.distance(self.data) + if self[constants.TYPE] == constants.SPOT_LIGHT: - self[constants.ANGLE] = api.light.angle(self.node) + self[constants.ANGLE] = api.light.angle(self.data) - def __init_mesh(self): - logger.debug('Object().__init_mesh()') + def _init_mesh(self): + """Initialize mesh attributes""" + logger.debug("Object()._init_mesh()") mesh = api.object.mesh(self.node, self.options) node = self.scene.geometry(mesh) if node: self[constants.GEOMETRY] = node[constants.UUID] else: - msg = 'Could not find Geometry() node for %s' + msg = "Could not find Geometry() node for %s" logger.error(msg, self.node) - def __node_setup(self): - logger.debug('Object().__node_setup()') + def _node_setup(self): + """Parse common node attributes of all objects""" + logger.debug("Object()._node_setup()") self[constants.NAME] = api.object.name(self.node) - self[constants.POSITION] = api.object.position( - self.node, self.options) - - self[constants.ROTATION] = api.object.rotation( - self.node, self.options) + transform = api.object.matrix(self.node, self.options) + matrix = [] + for col in range(0, 4): + for row in range(0, 4): + matrix.append(transform[row][col]) - self[constants.SCALE] = api.object.scale( - self.node, self.options) + self[constants.MATRIX] = matrix self[constants.VISIBLE] = api.object.visible(self.node) self[constants.TYPE] = api.object.node_type(self.node) if self.options.get(constants.MATERIALS): - logger.info('Parsing materials for %s', self.node) + logger.info("Parsing materials for %s", self.node) material_name = api.object.material(self.node) if material_name: - logger.info('Material found %s', material_name) + logger.info("Material found %s", material_name) material_inst = self.scene.material(material_name) self[constants.MATERIAL] = material_inst[constants.UUID] else: - logger.info('%s has no materials', self.node) + logger.info("%s has no materials", self.node) - casts_shadow = (constants.MESH, - constants.DIRECTIONAL_LIGHT, - constants.SPOT_LIGHT) + casts_shadow = (constants.MESH, + constants.DIRECTIONAL_LIGHT, + constants.SPOT_LIGHT) if self[constants.TYPE] in casts_shadow: - logger.info('Querying shadow casting for %s', self.node) + logger.info("Querying shadow casting for %s", self.node) self[constants.CAST_SHADOW] = \ api.object.cast_shadow(self.node) - + if self[constants.TYPE] == constants.MESH: - logger.info('Querying shadow receive for %s', self.node) + logger.info("Querying shadow receive for %s", self.node) self[constants.RECEIVE_SHADOW] = \ api.object.receive_shadow(self.node) camera = (constants.PERSPECTIVE_CAMERA, - constants.ORTHOGRAPHIC_CAMERA) + constants.ORTHOGRAPHIC_CAMERA) - lights = (constants.AMBIENT_LIGHT, constants.DIRECTIONAL_LIGHT, - constants.AREA_LIGHT, constants.POINT_LIGHT, - constants.SPOT_LIGHT, constants.HEMISPHERE_LIGHT) + lights = (constants.AMBIENT_LIGHT, + constants.DIRECTIONAL_LIGHT, + constants.AREA_LIGHT, constants.POINT_LIGHT, + constants.SPOT_LIGHT, constants.HEMISPHERE_LIGHT) if self[constants.TYPE] == constants.MESH: - self.__init_mesh() + self._init_mesh() elif self[constants.TYPE] in camera: - self.__init_camera() + self._init_camera() elif self[constants.TYPE] in lights: - self.__init_light() - - #for child in api.object.children(self.node, self.scene.valid_types): - # if not self.get(constants.CHILDREN): - # self[constants.CHILDREN] = [Object(child, parent=self)] - # else: - # self[constants.CHILDREN].append(Object(child, parent=self)) - - def __root_setup(self): - logger.debug('Object().__root_setup()') - self[constants.MATRIX] = [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] + self._init_light() + + if self.options.get(constants.HIERARCHY, False): + for child in api.object.children(self.node, self.scene.valid_types): + if not self.get(constants.CHILDREN): + self[constants.CHILDREN] = [Object(child, parent=self)] + else: + self[constants.CHILDREN].append(Object(child, parent=self)) + + def _root_setup(self): + """Applies to a root/scene object""" + logger.debug("Object()._root_setup()") + self[constants.MATRIX] = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 1] diff --git a/utils/exporters/blender/addons/io_three/exporter/scene.py b/utils/exporters/blender/addons/io_three/exporter/scene.py index cb182a8b401afb..cb78709ad703d3 100644 --- a/utils/exporters/blender/addons/io_three/exporter/scene.py +++ b/utils/exporters/blender/addons/io_three/exporter/scene.py @@ -4,14 +4,16 @@ base_classes, texture, material, - geometry, - object, + geometry, + object as object_, + utilities, io, api ) class Scene(base_classes.BaseScene): + """Class that handles the contruction of a Three scene""" _defaults = { constants.METADATA: constants.DEFAULT_METADATA.copy(), constants.GEOMETRIES: [], @@ -21,7 +23,7 @@ class Scene(base_classes.BaseScene): } def __init__(self, filepath, options=None): - logger.debug('Scene().__init__(%s, %s)', filepath, options) + logger.debug("Scene().__init__(%s, %s)", filepath, options) base_classes.BaseScene.__init__(self, filepath, options or {}) source_file = api.scene_name() @@ -30,73 +32,110 @@ def __init__(self, filepath, options=None): @property def valid_types(self): + """ + + :return: list of valid node types + + """ valid_types = [api.constants.MESH] + if self.options.get(constants.HIERARCHY, False): + valid_types.append(api.constants.EMPTY) + if self.options.get(constants.CAMERAS): - logger.info('Adding cameras to valid object types') + logger.info("Adding cameras to valid object types") valid_types.append(api.constants.CAMERA) if self.options.get(constants.LIGHTS): - logger.info('Adding lights to valid object types') + logger.info("Adding lights to valid object types") valid_types.append(api.constants.LAMP) return valid_types - def geometry(self, arg): - logger.debug('Scene().geometry(%s)', arg) - return self._find_node(arg, self[constants.GEOMETRIES]) + def geometry(self, value): + """Find a geometry node that matches either a name + or uuid value. + + :param value: name or uuid + :type value: str + + """ + logger.debug("Scene().geometry(%s)", value) + return _find_node(value, self[constants.GEOMETRIES]) + + def image(self, value): + """Find a image node that matches either a name + or uuid value. - def image(self, arg): - logger.debug('Scene().image%s)', arg) - return self._find_node(arg, self[constants.IMAGES]) + :param value: name or uuid + :type value: str - def material(self, arg): - logger.debug('Scene().material(%s)', arg) - return self._find_node(arg, self[constants.MATERIALS]) + """ + logger.debug("Scene().image%s)", value) + return _find_node(value, self[constants.IMAGES]) + + def material(self, value): + """Find a material node that matches either a name + or uuid value. + + :param value: name or uuid + :type value: str + + """ + logger.debug("Scene().material(%s)", value) + return _find_node(value, self[constants.MATERIALS]) def parse(self): - logger.debug('Scene().parse()') + """Execute the parsing of the scene""" + logger.debug("Scene().parse()") if self.options.get(constants.MAPS): - self.__parse_textures() + self._parse_textures() if self.options.get(constants.MATERIALS): - self.__parse_materials() + self._parse_materials() + + self._parse_geometries() + self._parse_objects() + + def texture(self, value): + """Find a texture node that matches either a name + or uuid value. - self.__parse_geometries() - self.__parse_objects() + :param value: name or uuid + :type value: str - def texture(self, arg): - logger.debug('Scene().texture(%s)', arg) - return self._find_node(arg, self[constants.TEXTURES]) + """ + logger.debug("Scene().texture(%s)", value) + return _find_node(value, self[constants.TEXTURES]) def write(self): - logger.debug('Scene().write()') + """Write the parsed scene to disk.""" + logger.debug("Scene().write()") data = {} - + embed_anim = self.options.get(constants.EMBED_ANIMATION, True) - embed = self.options[constants.EMBED_GEOMETRY] + embed = self.options.get(constants.EMBED_GEOMETRY, True) compression = self.options.get(constants.COMPRESSION) - extension = constants.EXTENSIONS.get(compression, + extension = constants.EXTENSIONS.get( + compression, constants.EXTENSIONS[constants.JSON]) export_dir = os.path.dirname(self.filepath) for key, value in self.items(): - + if key == constants.GEOMETRIES: geometries = [] - for geometry in value: + for geom in value: if not embed_anim: - geometry.write_animation(export_dir) + geom.write_animation(export_dir) + geom_data = geom.copy() if embed: - for each in value: - geometries.append(each.copy()) + geometries.append(geom_data) continue - geom_data = geometry.copy() - geo_type = geom_data[constants.TYPE].lower() if geo_type == constants.GEOMETRY.lower(): geom_data.pop(constants.DATA) @@ -104,10 +143,10 @@ def write(self): geom_data.pop(constants.ATTRIBUTES) geom_data.pop(constants.METADATA) - url = 'geometry.%s%s' % (geometry.node, extension) + url = 'geometry.%s%s' % (geom.node, extension) geometry_file = os.path.join(export_dir, url) - geometry.write(filepath=geometry_file) + geom.write(filepath=geometry_file) geom_data[constants.URL] = os.path.basename(url) geometries.append(geom_data) @@ -123,21 +162,14 @@ def write(self): io.dump(self.filepath, data, options=self.options) if self.options.get(constants.COPY_TEXTURES): + texture_folder = self.options.get(constants.TEXTURE_FOLDER) for geo in self[constants.GEOMETRIES]: - logger.info('Copying textures from %s', geo.node) - geo.copy_textures() - - def _find_node(self, arg, manifest): - for index in manifest: - uuid = index.get(constants.UUID) == arg - name = index.node == arg - if uuid or name: - return index - else: - logger.debug('No matching node for %s', arg) + logger.info("Copying textures from %s", geo.node) + geo.copy_textures(texture_folder) - def __parse_geometries(self): - logger.debug('Scene().__parse_geometries()') + def _parse_geometries(self): + """Locate all geometry nodes and parse them""" + logger.debug("Scene()._parse_geometries()") # this is an important step. please refer to the doc string # on the function for more information @@ -146,47 +178,80 @@ def __parse_geometries(self): # now iterate over all the extracted mesh nodes and parse each one for mesh in api.object.extracted_meshes(): - logger.info('Parsing geometry %s', mesh) + logger.info("Parsing geometry %s", mesh) geo = geometry.Geometry(mesh, self) geo.parse() geometries.append(geo) - logger.info('Added %d geometry nodes', len(geometries)) + logger.info("Added %d geometry nodes", len(geometries)) self[constants.GEOMETRIES] = geometries - def __parse_materials(self): - logger.debug('Scene().__parse_materials()') + def _parse_materials(self): + """Locate all non-orphaned materials and parse them""" + logger.debug("Scene()._parse_materials()") materials = [] for material_name in api.material.used_materials(): - logger.info('Parsing material %s', material_name) - materials.append(material.Material(material_name, parent=self)) + logger.info("Parsing material %s", material_name) + materials.append(material.Material(material_name, parent=self)) - logger.info('Added %d material nodes', len(materials)) + logger.info("Added %d material nodes", len(materials)) self[constants.MATERIALS] = materials - def __parse_objects(self): - logger.debug('Scene().__parse_objects()') - self[constants.OBJECT] = object.Object(None, parent=self) + def _parse_objects(self): + """Locate all valid objects in the scene and parse them""" + logger.debug("Scene()._parse_objects()") + try: + scene_name = self[constants.METADATA][constants.SOURCE_FILE] + except KeyError: + scene_name = constants.SCENE + self[constants.OBJECT] = object_.Object(None, parent=self) self[constants.OBJECT][constants.TYPE] = constants.SCENE.title() + self[constants.UUID] = utilities.id_from_name(scene_name) + + objects = [] + if self.options.get(constants.HIERARCHY, False): + nodes = api.object.assemblies(self.valid_types, self.options) + else: + nodes = api.object.nodes(self.valid_types, self.options) - objects = [] - for node in api.object.nodes(self.valid_types, self.options): - logger.info('Parsing object %s', node) - obj = object.Object(node, parent=self[constants.OBJECT]) + for node in nodes: + logger.info("Parsing object %s", node) + obj = object_.Object(node, parent=self[constants.OBJECT]) objects.append(obj) - logger.info('Added %d object nodes', len(objects)) + logger.info("Added %d object nodes", len(objects)) self[constants.OBJECT][constants.CHILDREN] = objects - def __parse_textures(self): - logger.debug('Scene().__parse_textures()') + def _parse_textures(self): + """Locate all non-orphaned textures and parse them""" + logger.debug("Scene()._parse_textures()") textures = [] for texture_name in api.texture.textures(): - logger.info('Parsing texture %s', texture_name) + logger.info("Parsing texture %s", texture_name) tex_inst = texture.Texture(texture_name, self) textures.append(tex_inst) - logger.info('Added %d texture nodes', len(textures)) + logger.info("Added %d texture nodes", len(textures)) self[constants.TEXTURES] = textures + + +def _find_node(value, manifest): + """Find a node that matches either a name + or uuid value. + + :param value: name or uuid + :param manifest: manifest of nodes to search + :type value: str + :type manifest: list + + """ + for index in manifest: + uuid = index.get(constants.UUID) == value + name = index.node == value + if uuid or name: + return index + else: + logger.debug("No matching node for %s", value) + diff --git a/utils/exporters/blender/addons/io_three/exporter/texture.py b/utils/exporters/blender/addons/io_three/exporter/texture.py index 2eafe25ff67cfb..cdf866b83612f2 100644 --- a/utils/exporters/blender/addons/io_three/exporter/texture.py +++ b/utils/exporters/blender/addons/io_three/exporter/texture.py @@ -3,8 +3,9 @@ class Texture(base_classes.BaseNode): + """Class that wraps a texture node""" def __init__(self, node, parent): - logger.debug('Texture().__init__(%s)', node) + logger.debug("Texture().__init__(%s)", node) base_classes.BaseNode.__init__(self, node, parent, constants.TEXTURE) img_inst = self.scene.image(api.texture.file_name(self.node)) @@ -29,4 +30,10 @@ def __init__(self, node, parent): @property def image(self): + """ + + :return: the image object of the current texture + :rtype: image.Image + + """ return self.scene.image(self[constants.IMAGE]) diff --git a/utils/exporters/blender/addons/io_three/exporter/utilities.py b/utils/exporters/blender/addons/io_three/exporter/utilities.py index 7bf5238617fd33..feb6b7d79afa5a 100644 --- a/utils/exporters/blender/addons/io_three/exporter/utilities.py +++ b/utils/exporters/blender/addons/io_three/exporter/utilities.py @@ -8,9 +8,15 @@ def bit_mask(flags): + """Generate a bit mask. + + :type flags: dict + :return: int + + """ bit = 0 - true = lambda x,y: (x | (1 << y)) - false = lambda x,y: (x & (~(1 << y))) + true = lambda x, y: (x | (1 << y)) + false = lambda x, y: (x & (~(1 << y))) for mask, position in constants.MASK.items(): func = true if flags.get(mask) else false @@ -20,45 +26,45 @@ def bit_mask(flags): def hash(value): + """Generate a hash from a given value + + :param value: + :rtype: str + + """ hash_ = hashlib.md5() hash_.update(repr(value).encode('utf8')) return hash_.hexdigest() def id(): - return str(uuid.uuid4()).upper() + """Generate a random UUID + :rtype: str -def rgb2int(rgb): - is_tuple = isinstance(rgb, tuple) - rgb = list(rgb) if is_tuple else rgb - - colour = (int(rgb[0]*255) << 16) + (int(rgb[1]*255) << 8) + int(rgb[2]*255) - return colour + """ + return str(uuid.uuid4()).upper() -def round_off(value, ndigits=ROUND): - is_tuple = isinstance(value, tuple) - is_list = isinstance(value, list) +def id_from_name(name): + """Generate a UUID using a name as the namespace - value = list(value) if is_tuple else value - value = [value] if not is_list and not is_tuple else value + :type name: str + :rtype: str - value = [round(val, ndigits) for val in value] + """ + return str(uuid.uuid3(uuid.NAMESPACE_DNS, name)).upper() - if is_tuple: - value = tuple(value) - elif not is_list: - value = value[0] - return value +def rgb2int(rgb): + """Convert a given rgb value to an integer + :type rgb: list|tuple + :rtype: int -def rounding(options): - round_off = options.get(constants.ENABLE_PRECISION) - if round_off: - round_val = options[constants.PRECISION] - else: - round_val = None + """ + is_tuple = isinstance(rgb, tuple) + rgb = list(rgb) if is_tuple else rgb - return (round_off, round_val) + colour = (int(rgb[0]*255) << 16) + (int(rgb[1]*255) << 8) + int(rgb[2]*255) + return colour diff --git a/utils/exporters/blender/addons/io_three/logger.py b/utils/exporters/blender/addons/io_three/logger.py index 7fd51f03e9fdfb..0c888df86897ac 100644 --- a/utils/exporters/blender/addons/io_three/logger.py +++ b/utils/exporters/blender/addons/io_three/logger.py @@ -15,7 +15,14 @@ constants.CRITICAL: logging.CRITICAL } + def init(filename, level=constants.DEBUG): + """Initialize the logger. + + :param filename: base name of the log file + :param level: logging level (Default value = DEBUG) + + """ global LOG_FILE LOG_FILE = os.path.join(tempfile.gettempdir(), filename) with open(LOG_FILE, 'w'): @@ -25,20 +32,21 @@ def init(filename, level=constants.DEBUG): LOGGER = logging.getLogger('Three.Export') LOGGER.setLevel(LEVELS[level]) - stream = logging.StreamHandler() - stream.setLevel(LEVELS[level]) + if not LOGGER.handlers: + stream = logging.StreamHandler() + stream.setLevel(LEVELS[level]) - format_ = '%(asctime)s - %(name)s - %(levelname)s: %(message)s' - formatter = logging.Formatter(format_) + format_ = '%(asctime)s - %(name)s - %(levelname)s: %(message)s' + formatter = logging.Formatter(format_) - stream.setFormatter(formatter) + stream.setFormatter(formatter) - file_handler = logging.FileHandler(LOG_FILE) - file_handler.setLevel(LEVELS[level]) - file_handler.setFormatter(formatter) + file_handler = logging.FileHandler(LOG_FILE) + file_handler.setLevel(LEVELS[level]) + file_handler.setFormatter(formatter) - LOGGER.addHandler(stream) - LOGGER.addHandler(file_handler) + LOGGER.addHandler(stream) + LOGGER.addHandler(file_handler) def info(*args): diff --git a/utils/exporters/blender/tests/blend/anim.blend b/utils/exporters/blender/tests/blend/anim.blend index 8a136463e860eb..c8e5095735d90a 100644 Binary files a/utils/exporters/blender/tests/blend/anim.blend and b/utils/exporters/blender/tests/blend/anim.blend differ diff --git a/utils/exporters/blender/tests/blend/scene_children.blend b/utils/exporters/blender/tests/blend/scene_children.blend new file mode 100644 index 00000000000000..5d857d8b0db436 Binary files /dev/null and b/utils/exporters/blender/tests/blend/scene_children.blend differ diff --git a/utils/exporters/blender/tests/blend/scene_orthographic_camera.blend b/utils/exporters/blender/tests/blend/scene_orthographic_camera.blend index 3e0bc12b353e76..4791a0547601ac 100644 Binary files a/utils/exporters/blender/tests/blend/scene_orthographic_camera.blend and b/utils/exporters/blender/tests/blend/scene_orthographic_camera.blend differ diff --git a/utils/exporters/blender/tests/blend/scene_perspective_camera.blend b/utils/exporters/blender/tests/blend/scene_perspective_camera.blend index 29e3e1e9677aa3..97e4fedb143a22 100644 Binary files a/utils/exporters/blender/tests/blend/scene_perspective_camera.blend and b/utils/exporters/blender/tests/blend/scene_perspective_camera.blend differ diff --git a/utils/exporters/blender/tests/blend/scene_spot_light.blend b/utils/exporters/blender/tests/blend/scene_spot_light.blend index 19b4b88e355730..c961989c6e406c 100644 Binary files a/utils/exporters/blender/tests/blend/scene_spot_light.blend and b/utils/exporters/blender/tests/blend/scene_spot_light.blend differ diff --git a/utils/exporters/blender/tests/scripts/exporter.py b/utils/exporters/blender/tests/scripts/exporter.py index e8f8659529f695..11c448a1b5ef7b 100755 --- a/utils/exporters/blender/tests/scripts/exporter.py +++ b/utils/exporters/blender/tests/scripts/exporter.py @@ -27,6 +27,8 @@ def parse_args(): def main(): args = parse_args() + args[constants.ENABLE_PRECISION] = True + args[constants.INDENT] = True if args[constants.SCENE]: io_three.exporter.export_scene(args['filepath'], args) else: diff --git a/utils/exporters/blender/tests/scripts/js/review.js b/utils/exporters/blender/tests/scripts/js/review.js index f8d48b6e1b1cf7..b48530c08fd9a6 100644 --- a/utils/exporters/blender/tests/scripts/js/review.js +++ b/utils/exporters/blender/tests/scripts/js/review.js @@ -99,6 +99,10 @@ function loadObject( data ) { camera = scene.children[ i ]; var container = document.getElementById( 'viewport' ); + + orbit = new THREE.OrbitControls( camera, container ); + orbit.addEventListener( 'change', render ); + var aspect = container.offsetWidth / container.offsetHeight; camera.aspect = aspect; camera.updateProjectionMatrix(); @@ -131,14 +135,14 @@ function loadGeometry( data, url ) { var material = new THREE.MeshFaceMaterial( data.materials ); var mesh; - if ( data.geometry.animation !== undefined ) { + if ( data.geometry.animations !== undefined && data.geometry.animations.length > 0 ) { console.log( 'loading animation' ); data.materials[ 0 ].skinning = true; - mesh = new THREE.SkinnedMesh( data.geometry, material, false); + mesh = new THREE.SkinnedMesh( data.geometry, material, false ); - var name = data.geometry.animation.name; - animation = new THREE.Animation( mesh, data.geometry.animation ); + var name = data.geometry.animations[0].name; + animation = new THREE.Animation( mesh, data.geometry.animations[0] ); } else { diff --git a/utils/exporters/blender/tests/scripts/test_geometry_normals.bash b/utils/exporters/blender/tests/scripts/test_geometry_normals.bash index 03d9b08b3dbcfb..89b923b96b8d56 100755 --- a/utils/exporters/blender/tests/scripts/test_geometry_normals.bash +++ b/utils/exporters/blender/tests/scripts/test_geometry_normals.bash @@ -4,5 +4,5 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source "$DIR/setup_test_env.bash" blender --background $BLEND/torusA.blend --python $PYSCRIPT -- \ - $JSON --vertices --faces --normals + $JSON --vertices --faces --normals --indent makereview $@ --tag $(tagname) diff --git a/utils/exporters/blender/tests/scripts/test_scene_children.bash b/utils/exporters/blender/tests/scripts/test_scene_children.bash new file mode 100755 index 00000000000000..f51c718e694be8 --- /dev/null +++ b/utils/exporters/blender/tests/scripts/test_scene_children.bash @@ -0,0 +1,9 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source "$DIR/setup_test_env.bash" + +blender --background $BLEND/scene_children.blend \ + --python $PYSCRIPT -- $JSON --vertices --faces --scene \ + --cameras --materials --embedGeometry --lights --cameras +makereview $@ --tag $(tagname) diff --git a/utils/exporters/blender/tests/scripts/test_scene_instancing.bash b/utils/exporters/blender/tests/scripts/test_scene_instancing.bash index 4e6cbed83ac8b5..5e93d6e1d0dfda 100755 --- a/utils/exporters/blender/tests/scripts/test_scene_instancing.bash +++ b/utils/exporters/blender/tests/scripts/test_scene_instancing.bash @@ -5,5 +5,5 @@ source "$DIR/setup_test_env.bash" blender --background $BLEND/scene_instancing.blend --python $PYSCRIPT -- \ $JSON --vertices --faces --scene --materials --enablePrecision \ - --precision 4 --embedGeometry + --precision 4 --embedGeometry --indent makereview $@ --tag $(tagname)