From da2936540a48774b043a1e617bddbdce5102e417 Mon Sep 17 00:00:00 2001 From: "Mr.doob" Date: Mon, 18 Dec 2017 14:17:37 -0800 Subject: [PATCH] r89 --- build/three.js | 7655 ++++++++++++++++++++++------------------- build/three.min.js | 1428 ++++---- build/three.module.js | 7637 +++++++++++++++++++++------------------- package.json | 2 +- src/constants.js | 2 +- 5 files changed, 8878 insertions(+), 7846 deletions(-) diff --git a/build/three.js b/build/three.js index 4b89d4c06f..1b795a61b4 100644 --- a/build/three.js +++ b/build/three.js @@ -185,7 +185,7 @@ } ); - var REVISION = '89dev'; + var REVISION = '89'; var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; var CullFaceNone = 0; var CullFaceBack = 1; @@ -10804,7 +10804,8 @@ geometries: {}, materials: {}, textures: {}, - images: {} + images: {}, + shapes: {} }; output.metadata = { @@ -10848,6 +10849,30 @@ object.geometry = serialize( meta.geometries, this.geometry ); + var parameters = this.geometry.parameters; + + if ( parameters !== undefined && parameters.shapes !== undefined ) { + + var shapes = parameters.shapes; + + if ( Array.isArray( shapes ) ) { + + for ( var i = 0, l = shapes.length; i < l; i ++ ) { + + var shape = shapes[ i ]; + + serialize( meta.shapes, shape ); + + } + + } else { + + serialize( meta.shapes, shapes ); + + } + + } + } if ( this.material !== undefined ) { @@ -10892,11 +10917,13 @@ var materials = extractFromCache( meta.materials ); var textures = extractFromCache( meta.textures ); var images = extractFromCache( meta.images ); + var shapes = extractFromCache( meta.shapes ); if ( geometries.length > 0 ) output.geometries = geometries; if ( materials.length > 0 ) output.materials = materials; if ( textures.length > 0 ) output.textures = textures; if ( images.length > 0 ) output.images = images; + if ( shapes.length > 0 ) output.shapes = shapes; } @@ -28903,6 +28930,16 @@ ShapeGeometry.prototype = Object.create( Geometry.prototype ); ShapeGeometry.prototype.constructor = ShapeGeometry; + ShapeGeometry.prototype.toJSON = function () { + + var data = Geometry.prototype.toJSON.call( this ); + + var shapes = this.parameters.shapes; + + return toJSON( shapes, data ); + + }; + // ShapeBufferGeometry function ShapeBufferGeometry( shapes, curveSegments ) { @@ -29038,6 +29075,42 @@ ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; + ShapeBufferGeometry.prototype.toJSON = function () { + + var data = BufferGeometry.prototype.toJSON.call( this ); + + var shapes = this.parameters.shapes; + + return toJSON( shapes, data ); + + }; + + // + + function toJSON( shapes, data ) { + + data.shapes = []; + + if ( Array.isArray( shapes ) ) { + + for ( var i = 0, l = shapes.length; i < l; i ++ ) { + + var shape = shapes[ i ]; + + data.shapes.push( shape.uuid ); + + } + + } else { + + data.shapes.push( shapes.uuid ); + + } + + return data; + + } + /** * @author WestLangley / http://github.com/WestLangley * @author Mugen87 / https://github.com/Mugen87 @@ -31299,2171 +31372,2254 @@ } ); /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - - function Light( color, intensity ) { + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible curve object + * + * Some common of curve methods: + * .getPoint( t, optionalTarget ), .getTangent( t ) + * .getPointAt( u, optionalTarget ), .getTangentAt( u ) + * .getPoints(), .getSpacedPoints() + * .getLength() + * .updateArcLengths() + * + * This following curves inherit from THREE.Curve: + * + * -- 2D curves -- + * THREE.ArcCurve + * THREE.CubicBezierCurve + * THREE.EllipseCurve + * THREE.LineCurve + * THREE.QuadraticBezierCurve + * THREE.SplineCurve + * + * -- 3D curves -- + * THREE.CatmullRomCurve3 + * THREE.CubicBezierCurve3 + * THREE.LineCurve3 + * THREE.QuadraticBezierCurve3 + * + * A series of curves can be represented as a THREE.CurvePath. + * + **/ - Object3D.call( this ); + /************************************************************** + * Abstract Curve base class + **************************************************************/ - this.type = 'Light'; + function Curve() { - this.color = new Color( color ); - this.intensity = intensity !== undefined ? intensity : 1; + this.type = 'Curve'; - this.receiveShadow = undefined; + this.arcLengthDivisions = 200; } - Light.prototype = Object.assign( Object.create( Object3D.prototype ), { + Object.assign( Curve.prototype, { - constructor: Light, + // Virtual base class method to overwrite and implement in subclasses + // - t [0 .. 1] - isLight: true, + getPoint: function ( /* t, optionalTarget */ ) { - copy: function ( source ) { + console.warn( 'THREE.Curve: .getPoint() not implemented.' ); + return null; - Object3D.prototype.copy.call( this, source ); + }, - this.color.copy( source.color ); - this.intensity = source.intensity; + // Get point at relative position in curve according to arc length + // - u [0 .. 1] - return this; + getPointAt: function ( u, optionalTarget ) { + + var t = this.getUtoTmapping( u ); + return this.getPoint( t, optionalTarget ); }, - toJSON: function ( meta ) { + // Get sequence of points using getPoint( t ) - var data = Object3D.prototype.toJSON.call( this, meta ); + getPoints: function ( divisions ) { - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; + if ( divisions === undefined ) divisions = 5; - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); + var points = []; - if ( this.distance !== undefined ) data.object.distance = this.distance; - if ( this.angle !== undefined ) data.object.angle = this.angle; - if ( this.decay !== undefined ) data.object.decay = this.decay; - if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; + for ( var d = 0; d <= divisions; d ++ ) { - if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); + points.push( this.getPoint( d / divisions ) ); - return data; + } - } + return points; - } ); + }, - /** - * @author alteredq / http://alteredqualia.com/ - */ + // Get sequence of points using getPointAt( u ) - function HemisphereLight( skyColor, groundColor, intensity ) { + getSpacedPoints: function ( divisions ) { - Light.call( this, skyColor, intensity ); + if ( divisions === undefined ) divisions = 5; - this.type = 'HemisphereLight'; + var points = []; - this.castShadow = undefined; + for ( var d = 0; d <= divisions; d ++ ) { - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + points.push( this.getPointAt( d / divisions ) ); - this.groundColor = new Color( groundColor ); + } - } + return points; - HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { + }, - constructor: HemisphereLight, + // Get total curve arc length - isHemisphereLight: true, + getLength: function () { - copy: function ( source ) { + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; - Light.prototype.copy.call( this, source ); + }, - this.groundColor.copy( source.groundColor ); + // Get list of cumulative segment lengths - return this; + getLengths: function ( divisions ) { - } + if ( divisions === undefined ) divisions = this.arcLengthDivisions; - } ); + if ( this.cacheArcLengths && + ( this.cacheArcLengths.length === divisions + 1 ) && + ! this.needsUpdate ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + return this.cacheArcLengths; - function LightShadow( camera ) { + } - this.camera = camera; + this.needsUpdate = false; - this.bias = 0; - this.radius = 1; + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; - this.mapSize = new Vector2( 512, 512 ); + cache.push( 0 ); - this.map = null; - this.matrix = new Matrix4(); + for ( p = 1; p <= divisions; p ++ ) { - } + current = this.getPoint( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; - Object.assign( LightShadow.prototype, { + } - copy: function ( source ) { + this.cacheArcLengths = cache; - this.camera = source.camera.clone(); + return cache; // { sums: cache, sum: sum }; Sum is in the last element. - this.bias = source.bias; - this.radius = source.radius; + }, - this.mapSize.copy( source.mapSize ); + updateArcLengths: function () { - return this; + this.needsUpdate = true; + this.getLengths(); }, - clone: function () { - - return new this.constructor().copy( this ); + // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant - }, + getUtoTmapping: function ( u, distance ) { - toJSON: function () { + var arcLengths = this.getLengths(); - var object = {}; + var i = 0, il = arcLengths.length; - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); + var targetArcLength; // The targeted u distance value to get - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; + if ( distance ) { - return object; + targetArcLength = distance; - } + } else { - } ); + targetArcLength = u * arcLengths[ il - 1 ]; - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function SpotLightShadow() { + // binary search for the index with largest value smaller than target u distance - LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); + var low = 0, high = il - 1, comparison; - } + while ( low <= high ) { - SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - constructor: SpotLightShadow, + comparison = arcLengths[ i ] - targetArcLength; - isSpotLightShadow: true, + if ( comparison < 0 ) { - update: function ( light ) { + low = i + 1; - var camera = this.camera; + } else if ( comparison > 0 ) { - var fov = _Math.RAD2DEG * 2 * light.angle; - var aspect = this.mapSize.width / this.mapSize.height; - var far = light.distance || camera.far; + high = i - 1; - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + } else { - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); + high = i; + break; - } + // DONE - } + } - } ); + } - /** - * @author alteredq / http://alteredqualia.com/ - */ + i = high; - function SpotLight( color, intensity, distance, angle, penumbra, decay ) { + if ( arcLengths[ i ] === targetArcLength ) { - Light.call( this, color, intensity ); + return i / ( il - 1 ); - this.type = 'SpotLight'; + } - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + // we could get finer grain at lengths, or use simple interpolation between two points - this.target = new Object3D(); + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; - Object.defineProperty( this, 'power', { - get: function () { + var segmentLength = lengthAfter - lengthBefore; - // intensity = power per solid angle. - // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - return this.intensity * Math.PI; + // determine where we are between the 'before' and 'after' points - }, - set: function ( power ) { + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - // intensity = power per solid angle. - // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - this.intensity = power / Math.PI; + // add that fractional amount to t - } - } ); + var t = ( i + segmentFraction ) / ( il - 1 ); - this.distance = ( distance !== undefined ) ? distance : 0; - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + return t; - this.shadow = new SpotLightShadow(); + }, - } + // Returns a unit vector tangent at t + // In case any sub curve does not implement its tangent derivation, + // 2 points a small delta apart will be used to find its gradient + // which seems to give a reasonable approximation - SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { + getTangent: function ( t ) { - constructor: SpotLight, + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; - isSpotLight: true, + // Capping in case of danger - copy: function ( source ) { + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; - Light.prototype.copy.call( this, source ); + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; + var vec = pt2.clone().sub( pt1 ); + return vec.normalize(); - this.target = source.target.clone(); + }, - this.shadow = source.shadow.clone(); + getTangentAt: function ( u ) { - return this; + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); - } + }, - } ); + computeFrenetFrames: function ( segments, closed ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + var normal = new Vector3(); - function PointLight( color, intensity, distance, decay ) { + var tangents = []; + var normals = []; + var binormals = []; - Light.call( this, color, intensity ); + var vec = new Vector3(); + var mat = new Matrix4(); - this.type = 'PointLight'; + var i, u, theta; - Object.defineProperty( this, 'power', { - get: function () { + // compute the tangent vectors for each segment on the curve - // intensity = power per solid angle. - // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - return this.intensity * 4 * Math.PI; + for ( i = 0; i <= segments; i ++ ) { - }, - set: function ( power ) { + u = i / segments; - // intensity = power per solid angle. - // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - this.intensity = power / ( 4 * Math.PI ); + tangents[ i ] = this.getTangentAt( u ); + tangents[ i ].normalize(); } - } ); - this.distance = ( distance !== undefined ) ? distance : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + // select an initial normal vector perpendicular to the first tangent vector, + // and in the direction of the minimum tangent xyz component - this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); + normals[ 0 ] = new Vector3(); + binormals[ 0 ] = new Vector3(); + var min = Number.MAX_VALUE; + var tx = Math.abs( tangents[ 0 ].x ); + var ty = Math.abs( tangents[ 0 ].y ); + var tz = Math.abs( tangents[ 0 ].z ); - } + if ( tx <= min ) { - PointLight.prototype = Object.assign( Object.create( Light.prototype ), { + min = tx; + normal.set( 1, 0, 0 ); - constructor: PointLight, + } - isPointLight: true, + if ( ty <= min ) { - copy: function ( source ) { + min = ty; + normal.set( 0, 1, 0 ); - Light.prototype.copy.call( this, source ); + } - this.distance = source.distance; - this.decay = source.decay; + if ( tz <= min ) { - this.shadow = source.shadow.clone(); + normal.set( 0, 0, 1 ); - return this; + } - } + vec.crossVectors( tangents[ 0 ], normal ).normalize(); - } ); + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - /** - * @author mrdoob / http://mrdoob.com/ - */ - function DirectionalLightShadow( ) { + // compute the slowly-varying normal and binormal vectors for each segment on the curve - LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + for ( i = 1; i <= segments; i ++ ) { - } + normals[ i ] = normals[ i - 1 ].clone(); - DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + binormals[ i ] = binormals[ i - 1 ].clone(); - constructor: DirectionalLightShadow + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - } ); + if ( vec.length() > Number.EPSILON ) { - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + vec.normalize(); - function DirectionalLight( color, intensity ) { + theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - Light.call( this, color, intensity ); + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - this.type = 'DirectionalLight'; + } - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - this.target = new Object3D(); + } - this.shadow = new DirectionalLightShadow(); + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - } + if ( closed === true ) { - DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { + theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); + theta /= segments; - constructor: DirectionalLight, + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - isDirectionalLight: true, + theta = - theta; - copy: function ( source ) { + } - Light.prototype.copy.call( this, source ); + for ( i = 1; i <= segments; i ++ ) { - this.target = source.target.clone(); + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - this.shadow = source.shadow.clone(); + } - return this; + } - } + return { + tangents: tangents, + normals: normals, + binormals: binormals + }; - } ); + }, - /** - * @author mrdoob / http://mrdoob.com/ - */ + clone: function () { - function AmbientLight( color, intensity ) { + return new this.constructor().copy( this ); - Light.call( this, color, intensity ); + }, - this.type = 'AmbientLight'; + copy: function ( source ) { - this.castShadow = undefined; + this.arcLengthDivisions = source.arcLengthDivisions; - } + return this; - AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { + }, - constructor: AmbientLight, + toJSON: function () { - isAmbientLight: true + var data = { + metadata: { + version: 4.5, + type: 'Curve', + generator: 'Curve.toJSON' + } + }; - } ); + data.arcLengthDivisions = this.arcLengthDivisions; + data.type = this.type; - /** - * @author abelnation / http://github.com/abelnation - */ + return data; - function RectAreaLight( color, intensity, width, height ) { + }, - Light.call( this, color, intensity ); + fromJSON: function ( json ) { - this.type = 'RectAreaLight'; + this.arcLengthDivisions = json.arcLengthDivisions; - this.position.set( 0, 1, 0 ); - this.updateMatrix(); + return this; - this.width = ( width !== undefined ) ? width : 10; - this.height = ( height !== undefined ) ? height : 10; + } - // TODO (abelnation): distance/decay + } ); - // TODO (abelnation): update method for RectAreaLight to update transform to lookat target + function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - // TODO (abelnation): shadows + Curve.call( this ); + + this.type = 'EllipseCurve'; + + this.aX = aX || 0; + this.aY = aY || 0; + + this.xRadius = xRadius || 1; + this.yRadius = yRadius || 1; + + this.aStartAngle = aStartAngle || 0; + this.aEndAngle = aEndAngle || 2 * Math.PI; + + this.aClockwise = aClockwise || false; + + this.aRotation = aRotation || 0; } - // TODO (abelnation): RectAreaLight update when light shape is changed - RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { + EllipseCurve.prototype = Object.create( Curve.prototype ); + EllipseCurve.prototype.constructor = EllipseCurve; - constructor: RectAreaLight, + EllipseCurve.prototype.isEllipseCurve = true; - isRectAreaLight: true, + EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) { - copy: function ( source ) { + var point = optionalTarget || new Vector2(); - Light.prototype.copy.call( this, source ); + var twoPi = Math.PI * 2; + var deltaAngle = this.aEndAngle - this.aStartAngle; + var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - this.width = source.width; - this.height = source.height; + // ensures that deltaAngle is 0 .. 2 PI + while ( deltaAngle < 0 ) deltaAngle += twoPi; + while ( deltaAngle > twoPi ) deltaAngle -= twoPi; - return this; + if ( deltaAngle < Number.EPSILON ) { - }, + if ( samePoints ) { - toJSON: function ( meta ) { + deltaAngle = 0; - var data = Light.prototype.toJSON.call( this, meta ); + } else { - data.object.width = this.width; - data.object.height = this.height; + deltaAngle = twoPi; - return data; + } } - } ); + if ( this.aClockwise === true && ! samePoints ) { - /** - * - * A Track that interpolates Strings - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + if ( deltaAngle === twoPi ) { - function StringKeyframeTrack( name, times, values, interpolation ) { + deltaAngle = - twoPi; - KeyframeTrack.call( this, name, times, values, interpolation ); + } else { - } + deltaAngle = deltaAngle - twoPi; - StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + } - constructor: StringKeyframeTrack, + } - ValueTypeName: 'string', - ValueBufferType: Array, + var angle = this.aStartAngle + t * deltaAngle; + var x = this.aX + this.xRadius * Math.cos( angle ); + var y = this.aY + this.yRadius * Math.sin( angle ); - DefaultInterpolation: InterpolateDiscrete, + if ( this.aRotation !== 0 ) { - InterpolantFactoryMethodLinear: undefined, + var cos = Math.cos( this.aRotation ); + var sin = Math.sin( this.aRotation ); - InterpolantFactoryMethodSmooth: undefined + var tx = x - this.aX; + var ty = y - this.aY; - } ); + // Rotate the point about the center of the ellipse. + x = tx * cos - ty * sin + this.aX; + y = tx * sin + ty * cos + this.aY; - /** - * - * A Track of Boolean keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + } - function BooleanKeyframeTrack( name, times, values ) { + return point.set( x, y ); - KeyframeTrack.call( this, name, times, values ); + }; - } + EllipseCurve.prototype.copy = function ( source ) { - BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + Curve.prototype.copy.call( this, source ); - constructor: BooleanKeyframeTrack, + this.aX = source.aX; + this.aY = source.aY; - ValueTypeName: 'bool', - ValueBufferType: Array, + this.xRadius = source.xRadius; + this.yRadius = source.yRadius; - DefaultInterpolation: InterpolateDiscrete, + this.aStartAngle = source.aStartAngle; + this.aEndAngle = source.aEndAngle; - InterpolantFactoryMethodLinear: undefined, - InterpolantFactoryMethodSmooth: undefined + this.aClockwise = source.aClockwise; - // Note: Actually this track could have a optimized / compressed - // representation of a single value and a custom interpolant that - // computes "firstValue ^ isOdd( index )". + this.aRotation = source.aRotation; - } ); + return this; - /** - * Abstract base class of interpolants over parametric samples. - * - * The parameter domain is one dimensional, typically the time or a path - * along a curve defined by the data. - * - * The sample values can have any dimensionality and derived classes may - * apply special interpretations to the data. - * - * This class provides the interval seek in a Template Method, deferring - * the actual interpolation to derived classes. - * - * Time complexity is O(1) for linear access crossing at most two points - * and O(log N) for random access, where N is the number of positions. - * - * References: - * - * http://www.oodesign.com/template-method-pattern.html - * - * @author tschw - */ + }; - function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; + EllipseCurve.prototype.toJSON = function () { - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; + var data = Curve.prototype.toJSON.call( this ); - } + data.aX = this.aX; + data.aY = this.aY; - Object.assign( Interpolant.prototype, { + data.xRadius = this.xRadius; + data.yRadius = this.yRadius; - evaluate: function ( t ) { + data.aStartAngle = this.aStartAngle; + data.aEndAngle = this.aEndAngle; - var pp = this.parameterPositions, - i1 = this._cachedIndex, + data.aClockwise = this.aClockwise; - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; + data.aRotation = this.aRotation; - validate_interval: { + return data; - seek: { + }; - var right; + EllipseCurve.prototype.fromJSON = function ( json ) { - linear_scan: { + Curve.prototype.fromJSON.call( this, json ); - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { + this.aX = json.aX; + this.aY = json.aY; - for ( var giveUpAt = i1 + 2; ; ) { + this.xRadius = json.xRadius; + this.yRadius = json.yRadius; - if ( t1 === undefined ) { + this.aStartAngle = json.aStartAngle; + this.aEndAngle = json.aEndAngle; - if ( t < t0 ) break forward_scan; + this.aClockwise = json.aClockwise; - // after end + this.aRotation = json.aRotation; - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t, t0 ); + return this; - } + }; - if ( i1 === giveUpAt ) break; // this loop + function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - t0 = t1; - t1 = pp[ ++ i1 ]; + EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - if ( t < t1 ) { + this.type = 'ArcCurve'; - // we have arrived at the sought interval - break seek; + } - } + ArcCurve.prototype = Object.create( EllipseCurve.prototype ); + ArcCurve.prototype.constructor = ArcCurve; - } + ArcCurve.prototype.isArcCurve = true; - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; + /** + * @author zz85 https://github.com/zz85 + * + * Centripetal CatmullRom Curve - which is useful for avoiding + * cusps and self-intersections in non-uniform catmull rom curves. + * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + * + * curve.type accepts centripetal(default), chordal and catmullrom + * curve.tension is used for catmullrom which defaults to 0.5 + */ - } - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { + /* + Based on an optimized c++ solution in + - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ + - http://ideone.com/NoEbVM - // looping? + This CubicPoly class could be used for reusing some variables and calculations, + but for three.js curve use, it could be possible inlined and flatten into a single function call + which can be placed in CurveUtils. + */ - var t1global = pp[ 1 ]; + function CubicPoly() { - if ( t < t1global ) { + var c0 = 0, c1 = 0, c2 = 0, c3 = 0; - i1 = 2; // + 1, using the scan for the details - t0 = t1global; + /* + * Compute coefficients for a cubic polynomial + * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 + * such that + * p(0) = x0, p(1) = x1 + * and + * p'(0) = t0, p'(1) = t1. + */ + function init( x0, x1, t0, t1 ) { - } + c0 = x0; + c1 = t0; + c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; + c3 = 2 * x0 - 2 * x1 + t0 + t1; - // linear reverse scan + } - for ( var giveUpAt = i1 - 2; ; ) { + return { - if ( t0 === undefined ) { + initCatmullRom: function ( x0, x1, x2, x3, tension ) { - // before start + init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); + }, - } + initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - if ( i1 === giveUpAt ) break; // this loop + // compute tangents when parameterized in [t1,t2] + var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; + var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - t1 = t0; - t0 = pp[ -- i1 - 1 ]; + // rescale tangents for parametrization in [0,1] + t1 *= dt1; + t2 *= dt1; - if ( t >= t0 ) { + init( x1, x2, t1, t2 ); - // we have arrived at the sought interval - break seek; + }, - } + calc: function ( t ) { - } + var t2 = t * t; + var t3 = t2 * t; + return c0 + c1 * t + c2 * t2 + c3 * t3; - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; + } - } + }; - // the interval is valid + } - break validate_interval; + // - } // linear scan + var tmp = new Vector3(); + var px = new CubicPoly(); + var py = new CubicPoly(); + var pz = new CubicPoly(); - // binary search + function CatmullRomCurve3( points, closed, curveType, tension ) { - while ( i1 < right ) { + Curve.call( this ); - var mid = ( i1 + right ) >>> 1; + this.type = 'CatmullRomCurve3'; - if ( t < pp[ mid ] ) { + this.points = points || []; + this.closed = closed || false; + this.curveType = curveType || 'centripetal'; + this.tension = tension || 0.5; - right = mid; + } - } else { + CatmullRomCurve3.prototype = Object.create( Curve.prototype ); + CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; - i1 = mid + 1; + CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; - } + CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector3(); - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; + var points = this.points; + var l = points.length; - // check boundary cases, again + var p = ( l - ( this.closed ? 0 : 1 ) ) * t; + var intPoint = Math.floor( p ); + var weight = p - intPoint; - if ( t0 === undefined ) { + if ( this.closed ) { - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - } + } else if ( weight === 0 && intPoint === l - 1 ) { - if ( t1 === undefined ) { + intPoint = l - 2; + weight = 1; - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t0, t ); + } - } + var p0, p1, p2, p3; // 4 points - } // seek + if ( this.closed || intPoint > 0 ) { - this._cachedIndex = i1; + p0 = points[ ( intPoint - 1 ) % l ]; - this.intervalChanged_( i1, t0, t1 ); + } else { - } // validate_interval + // extrapolate first point + tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); + p0 = tmp; - return this.interpolate_( i1, t0, t, t1 ); + } - }, + p1 = points[ intPoint % l ]; + p2 = points[ ( intPoint + 1 ) % l ]; - settings: null, // optional, subclass-specific settings structure - // Note: The indirection allows central control of many interpolants. + if ( this.closed || intPoint + 2 < l ) { - // --- Protected interface + p3 = points[ ( intPoint + 2 ) % l ]; - DefaultSettings_: {}, + } else { - getSettings_: function () { + // extrapolate last point + tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); + p3 = tmp; - return this.settings || this.DefaultSettings_; + } - }, + if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - copySampleValue_: function ( index ) { + // init Centripetal / Chordal Catmull-Rom + var pow = this.curveType === 'chordal' ? 0.5 : 0.25; + var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); + var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); + var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - // copies a sample value to the result buffer + // safety check for repeated points + if ( dt1 < 1e-4 ) dt1 = 1.0; + if ( dt0 < 1e-4 ) dt0 = dt1; + if ( dt2 < 1e-4 ) dt2 = dt1; - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; + px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); + py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); + pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - for ( var i = 0; i !== stride; ++ i ) { + } else if ( this.curveType === 'catmullrom' ) { - result[ i ] = values[ offset + i ]; + px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); + py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); + pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); - } + } - return result; + point.set( + px.calc( weight ), + py.calc( weight ), + pz.calc( weight ) + ); - }, + return point; - // Template methods for derived classes: + }; - interpolate_: function ( /* i1, t0, t, t1 */ ) { + CatmullRomCurve3.prototype.copy = function ( source ) { - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer + Curve.prototype.copy.call( this, source ); - }, + this.points = []; - intervalChanged_: function ( /* i1, t0, t1 */ ) { + for ( var i = 0, l = source.points.length; i < l; i ++ ) { - // empty + var point = source.points[ i ]; + + this.points.push( point.clone() ); } - } ); + this.closed = source.closed; + this.curveType = source.curveType; + this.tension = source.tension; - //!\ DECLARE ALIAS AFTER assign prototype ! - Object.assign( Interpolant.prototype, { + return this; - //( 0, t, t0 ), returns this.resultBuffer - beforeStart_: Interpolant.prototype.copySampleValue_, + }; - //( N-1, tN-1, t ), returns this.resultBuffer - afterEnd_: Interpolant.prototype.copySampleValue_, + CatmullRomCurve3.prototype.toJSON = function () { - } ); + var data = Curve.prototype.toJSON.call( this ); - /** - * Spherical linear unit quaternion interpolant. - * - * @author tschw - */ + data.points = []; - function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + for ( var i = 0, l = this.points.length; i < l; i ++ ) { - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + var point = this.points[ i ]; + data.points.push( point.toArray() ); - } + } - QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + data.closed = this.closed; + data.curveType = this.curveType; + data.tension = this.tension; - constructor: QuaternionLinearInterpolant, + return data; - interpolate_: function ( i1, t0, t, t1 ) { + }; - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + CatmullRomCurve3.prototype.fromJSON = function ( json ) { - offset = i1 * stride, + Curve.prototype.fromJSON.call( this, json ); - alpha = ( t - t0 ) / ( t1 - t0 ); + this.points = []; - for ( var end = offset + stride; offset !== end; offset += 4 ) { + for ( var i = 0, l = json.points.length; i < l; i ++ ) { - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); + var point = json.points[ i ]; + this.points.push( new Vector3().fromArray( point ) ); - } + } - return result; + this.closed = json.closed; + this.curveType = json.curveType; + this.tension = json.tension; - } + return this; - } ); + }; /** + * @author zz85 / http://www.lab4games.net/zz85/blog * - * A Track of quaternion keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw + * Bezier Curves formulas obtained from + * http://en.wikipedia.org/wiki/Bézier_curve */ - function QuaternionKeyframeTrack( name, times, values, interpolation ) { + function CatmullRom( t, p0, p1, p2, p3 ) { - KeyframeTrack.call( this, name, times, values, interpolation ); + var v0 = ( p2 - p0 ) * 0.5; + var v1 = ( p3 - p1 ) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; } - QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + // - constructor: QuaternionKeyframeTrack, + function QuadraticBezierP0( t, p ) { - ValueTypeName: 'quaternion', + var k = 1 - t; + return k * k * p; - // ValueBufferType is inherited + } - DefaultInterpolation: InterpolateLinear, + function QuadraticBezierP1( t, p ) { - InterpolantFactoryMethodLinear: function ( result ) { + return 2 * ( 1 - t ) * t * p; - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); + } - }, + function QuadraticBezierP2( t, p ) { - InterpolantFactoryMethodSmooth: undefined // not yet implemented + return t * t * p; - } ); + } - /** - * - * A Track of keyframe values that represent color. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - - function ColorKeyframeTrack( name, times, values, interpolation ) { + function QuadraticBezier( t, p0, p1, p2 ) { - KeyframeTrack.call( this, name, times, values, interpolation ); + return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + + QuadraticBezierP2( t, p2 ); } - ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - - constructor: ColorKeyframeTrack, + // - ValueTypeName: 'color' + function CubicBezierP0( t, p ) { - // ValueBufferType is inherited + var k = 1 - t; + return k * k * k * p; - // DefaultInterpolation is inherited + } - // Note: Very basic implementation and nothing special yet. - // However, this is the place for color space parameterization. + function CubicBezierP1( t, p ) { - } ); + var k = 1 - t; + return 3 * k * k * t * p; - /** - * - * A Track of numeric keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + } - function NumberKeyframeTrack( name, times, values, interpolation ) { + function CubicBezierP2( t, p ) { - KeyframeTrack.call( this, name, times, values, interpolation ); + return 3 * ( 1 - t ) * t * t * p; } - NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + function CubicBezierP3( t, p ) { - constructor: NumberKeyframeTrack, + return t * t * t * p; - ValueTypeName: 'number' + } - // ValueBufferType is inherited + function CubicBezier( t, p0, p1, p2, p3 ) { - // DefaultInterpolation is inherited + return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + + CubicBezierP3( t, p3 ); - } ); + } - /** - * Fast and simple cubic spline interpolant. - * - * It was derived from a Hermitian construction setting the first derivative - * at each sample position to the linear slope between neighboring positions - * over their parameter interval. - * - * @author tschw - */ + function CubicBezierCurve( v0, v1, v2, v3 ) { - function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + Curve.call( this ); - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + this.type = 'CubicBezierCurve'; - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; + this.v0 = v0 || new Vector2(); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); + this.v3 = v3 || new Vector2(); } - CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + CubicBezierCurve.prototype = Object.create( Curve.prototype ); + CubicBezierCurve.prototype.constructor = CubicBezierCurve; - constructor: CubicInterpolant, + CubicBezierCurve.prototype.isCubicBezierCurve = true; - DefaultSettings_: { + CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding + var point = optionalTarget || new Vector2(); - }, + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - intervalChanged_: function ( i1, t0, t1 ) { + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) + ); - var pp = this.parameterPositions, - iPrev = i1 - 2, - iNext = i1 + 1, + return point; - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; + }; - if ( tPrev === undefined ) { + CubicBezierCurve.prototype.copy = function ( source ) { - switch ( this.getSettings_().endingStart ) { + Curve.prototype.copy.call( this, source ); - case ZeroSlopeEnding: + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; + return this; - break; + }; - case WrapAroundEnding: + CubicBezierCurve.prototype.toJSON = function () { - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + var data = Curve.prototype.toJSON.call( this ); - break; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - default: // ZeroCurvatureEnding + return data; - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; + }; - } + CubicBezierCurve.prototype.fromJSON = function ( json ) { - } + Curve.prototype.fromJSON.call( this, json ); - if ( tNext === undefined ) { + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); - switch ( this.getSettings_().endingEnd ) { + return this; - case ZeroSlopeEnding: + }; - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; + function CubicBezierCurve3( v0, v1, v2, v3 ) { - break; + Curve.call( this ); - case WrapAroundEnding: + this.type = 'CubicBezierCurve3'; - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; + this.v0 = v0 || new Vector3(); + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); + this.v3 = v3 || new Vector3(); - break; + } - default: // ZeroCurvatureEnding + CubicBezierCurve3.prototype = Object.create( Curve.prototype ); + CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; + CubicBezierCurve3.prototype.isCubicBezierCurve3 = true; - } + CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector3(); - var halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), + CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) + ); - }, + return point; - interpolate_: function ( i1, t0, t, t1 ) { + }; - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + CubicBezierCurve3.prototype.copy = function ( source ) { - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, + Curve.prototype.copy.call( this, source ); - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - // evaluate polynomials + return this; - var sP = - wP * ppp + 2 * wP * pp - wP * p; - var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - var sN = wN * ppp - wN * pp; + }; - // combine data linearly + CubicBezierCurve3.prototype.toJSON = function () { - for ( var i = 0; i !== stride; ++ i ) { + var data = Curve.prototype.toJSON.call( this ); - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - } + return data; - return result; + }; - } + CubicBezierCurve3.prototype.fromJSON = function ( json ) { - } ); + Curve.prototype.fromJSON.call( this, json ); - /** - * @author tschw - */ + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); - function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + return this; - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + }; - } + function LineCurve( v1, v2 ) { - LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + Curve.call( this ); - constructor: LinearInterpolant, + this.type = 'LineCurve'; - interpolate_: function ( i1, t0, t, t1 ) { + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + } - offset1 = i1 * stride, - offset0 = offset1 - stride, + LineCurve.prototype = Object.create( Curve.prototype ); + LineCurve.prototype.constructor = LineCurve; - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; + LineCurve.prototype.isLineCurve = true; - for ( var i = 0; i !== stride; ++ i ) { + LineCurve.prototype.getPoint = function ( t, optionalTarget ) { - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; + var point = optionalTarget || new Vector2(); - } + if ( t === 1 ) { - return result; + point.copy( this.v2 ); + + } else { + + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); } - } ); + return point; - /** - * - * Interpolant that evaluates to the sample value at the position preceeding - * the parameter. - * - * @author tschw - */ + }; - function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + // Line curve is linear, so we can overwrite default getPointAt - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + LineCurve.prototype.getPointAt = function ( u, optionalTarget ) { - } + return this.getPoint( u, optionalTarget ); - DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + }; - constructor: DiscreteInterpolant, + LineCurve.prototype.getTangent = function ( /* t */ ) { - interpolate_: function ( i1 /*, t0, t, t1 */ ) { + var tangent = this.v2.clone().sub( this.v1 ); - return this.copySampleValue_( i1 - 1 ); + return tangent.normalize(); - } + }; - } ); + LineCurve.prototype.copy = function ( source ) { - /** - * @author tschw - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ + Curve.prototype.copy.call( this, source ); - var AnimationUtils = { + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - // same as Array.prototype.slice, but also works on typed arrays - arraySlice: function ( array, from, to ) { + return this; - if ( AnimationUtils.isTypedArray( array ) ) { + }; - // in ios9 array.subarray(from, undefined) will return empty array - // but array.subarray(from) or array.subarray(from, len) is correct - return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) ); + LineCurve.prototype.toJSON = function () { - } + var data = Curve.prototype.toJSON.call( this ); - return array.slice( from, to ); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - }, + return data; - // converts an array to a specific type - convertArray: function ( array, type, forceClone ) { + }; - if ( ! array || // let 'undefined' and 'null' pass - ! forceClone && array.constructor === type ) return array; + LineCurve.prototype.fromJSON = function ( json ) { - if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + Curve.prototype.fromJSON.call( this, json ); - return new type( array ); // create typed array + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - } + return this; - return Array.prototype.slice.call( array ); // create Array + }; - }, + function LineCurve3( v1, v2 ) { - isTypedArray: function ( object ) { + Curve.call( this ); - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); + this.type = 'LineCurve3'; - }, + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); - // returns an array by which times and values can be sorted - getKeyframeOrder: function ( times ) { + } - function compareTime( i, j ) { + LineCurve3.prototype = Object.create( Curve.prototype ); + LineCurve3.prototype.constructor = LineCurve3; - return times[ i ] - times[ j ]; + LineCurve3.prototype.isLineCurve3 = true; - } + LineCurve3.prototype.getPoint = function ( t, optionalTarget ) { - var n = times.length; - var result = new Array( n ); - for ( var i = 0; i !== n; ++ i ) result[ i ] = i; + var point = optionalTarget || new Vector3(); - result.sort( compareTime ); + if ( t === 1 ) { - return result; + point.copy( this.v2 ); - }, + } else { - // uses the array previously returned by 'getKeyframeOrder' to sort data - sortedArray: function ( values, stride, order ) { + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); - var nValues = values.length; - var result = new values.constructor( nValues ); + } - for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + return point; - var srcOffset = order[ i ] * stride; + }; - for ( var j = 0; j !== stride; ++ j ) { + // Line curve is linear, so we can overwrite default getPointAt - result[ dstOffset ++ ] = values[ srcOffset + j ]; + LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) { - } + return this.getPoint( u, optionalTarget ); - } + }; - return result; + LineCurve3.prototype.copy = function ( source ) { - }, + Curve.prototype.copy.call( this, source ); - // function for parsing AOS keyframe formats - flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - var i = 1, key = jsonKeys[ 0 ]; + return this; - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + }; - key = jsonKeys[ i ++ ]; + LineCurve3.prototype.toJSON = function () { - } + var data = Curve.prototype.toJSON.call( this ); - if ( key === undefined ) return; // no data + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - var value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data + return data; - if ( Array.isArray( value ) ) { + }; - do { + LineCurve3.prototype.fromJSON = function ( json ) { - value = key[ valuePropertyName ]; + Curve.prototype.fromJSON.call( this, json ); - if ( value !== undefined ) { + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - times.push( key.time ); - values.push.apply( values, value ); // push all elements + return this; - } + }; - key = jsonKeys[ i ++ ]; + function QuadraticBezierCurve( v0, v1, v2 ) { - } while ( key !== undefined ); + Curve.call( this ); - } else if ( value.toArray !== undefined ) { + this.type = 'QuadraticBezierCurve'; - // ...assume THREE.Math-ish + this.v0 = v0 || new Vector2(); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); - do { + } - value = key[ valuePropertyName ]; + QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); + QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; - if ( value !== undefined ) { + QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; - times.push( key.time ); - value.toArray( values, values.length ); + QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector2(); - key = jsonKeys[ i ++ ]; + var v0 = this.v0, v1 = this.v1, v2 = this.v2; - } while ( key !== undefined ); + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ) + ); - } else { + return point; - // otherwise push as-is + }; - do { + QuadraticBezierCurve.prototype.copy = function ( source ) { - value = key[ valuePropertyName ]; + Curve.prototype.copy.call( this, source ); - if ( value !== undefined ) { + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - times.push( key.time ); - values.push( value ); + return this; - } + }; - key = jsonKeys[ i ++ ]; + QuadraticBezierCurve.prototype.toJSON = function () { - } while ( key !== undefined ); + var data = Curve.prototype.toJSON.call( this ); - } + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - } + return data; }; - /** - * - * A timed sequence of keyframes for a specific property. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + QuadraticBezierCurve.prototype.fromJSON = function ( json ) { - function KeyframeTrack( name, times, values, interpolation ) { + Curve.prototype.fromJSON.call( this, json ); - if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); - if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - this.name = name; + return this; - this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); - this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); + }; - this.setInterpolation( interpolation || this.DefaultInterpolation ); + function QuadraticBezierCurve3( v0, v1, v2 ) { - this.validate(); - this.optimize(); + Curve.call( this ); - } + this.type = 'QuadraticBezierCurve3'; - // Static methods: + this.v0 = v0 || new Vector3(); + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); - Object.assign( KeyframeTrack, { + } - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): + QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); + QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; - parse: function ( json ) { + QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; - if ( json.type === undefined ) { + QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); + var point = optionalTarget || new Vector3(); - } + var v0 = this.v0, v1 = this.v1, v2 = this.v2; - var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type ); + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ), + QuadraticBezier( t, v0.z, v1.z, v2.z ) + ); - if ( json.times === undefined ) { + return point; - var times = [], values = []; + }; - AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); + QuadraticBezierCurve3.prototype.copy = function ( source ) { - json.times = times; - json.values = values; + Curve.prototype.copy.call( this, source ); - } + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { + return this; - return trackType.parse( json ); + }; - } else { + QuadraticBezierCurve3.prototype.toJSON = function () { - // by default, we assume a constructor compatible with the base - return new trackType( json.name, json.times, json.values, json.interpolation ); + var data = Curve.prototype.toJSON.call( this ); - } + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - }, + return data; - toJSON: function ( track ) { + }; - var trackType = track.constructor; + QuadraticBezierCurve3.prototype.fromJSON = function ( json ) { - var json; + Curve.prototype.fromJSON.call( this, json ); - // derived classes can define a static toJSON method - if ( trackType.toJSON !== undefined ) { + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - json = trackType.toJSON( track ); + return this; - } else { + }; - // by default, we assume the data can be serialized as-is - json = { + function SplineCurve( points /* array of Vector2 */ ) { - 'name': track.name, - 'times': AnimationUtils.convertArray( track.times, Array ), - 'values': AnimationUtils.convertArray( track.values, Array ) + Curve.call( this ); - }; + this.type = 'SplineCurve'; - var interpolation = track.getInterpolation(); + this.points = points || []; - if ( interpolation !== track.DefaultInterpolation ) { + } - json.interpolation = interpolation; + SplineCurve.prototype = Object.create( Curve.prototype ); + SplineCurve.prototype.constructor = SplineCurve; - } + SplineCurve.prototype.isSplineCurve = true; - } + SplineCurve.prototype.getPoint = function ( t, optionalTarget ) { - json.type = track.ValueTypeName; // mandatory + var point = optionalTarget || new Vector2(); - return json; + var points = this.points; + var p = ( points.length - 1 ) * t; - }, + var intPoint = Math.floor( p ); + var weight = p - intPoint; - _getTrackTypeForValueTypeName: function ( typeName ) { + var p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; + var p1 = points[ intPoint ]; + var p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; + var p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - switch ( typeName.toLowerCase() ) { + point.set( + CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), + CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) + ); - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': + return point; - return NumberKeyframeTrack; + }; - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': + SplineCurve.prototype.copy = function ( source ) { - return VectorKeyframeTrack; + Curve.prototype.copy.call( this, source ); - case 'color': + this.points = []; - return ColorKeyframeTrack; + for ( var i = 0, l = source.points.length; i < l; i ++ ) { - case 'quaternion': + var point = source.points[ i ]; - return QuaternionKeyframeTrack; + this.points.push( point.clone() ); - case 'bool': - case 'boolean': + } - return BooleanKeyframeTrack; + return this; - case 'string': + }; - return StringKeyframeTrack; + SplineCurve.prototype.toJSON = function () { - } + var data = Curve.prototype.toJSON.call( this ); - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); + data.points = []; + + for ( var i = 0, l = this.points.length; i < l; i ++ ) { + + var point = this.points[ i ]; + data.points.push( point.toArray() ); } - } ); + return data; - Object.assign( KeyframeTrack.prototype, { + }; - constructor: KeyframeTrack, + SplineCurve.prototype.fromJSON = function ( json ) { - TimeBufferType: Float32Array, + Curve.prototype.fromJSON.call( this, json ); - ValueBufferType: Float32Array, + this.points = []; - DefaultInterpolation: InterpolateLinear, + for ( var i = 0, l = json.points.length; i < l; i ++ ) { - InterpolantFactoryMethodDiscrete: function ( result ) { + var point = json.points[ i ]; + this.points.push( new Vector2().fromArray( point ) ); - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); + } - }, + return this; - InterpolantFactoryMethodLinear: function ( result ) { + }; - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); - }, - InterpolantFactoryMethodSmooth: function ( result ) { + var Curves = Object.freeze({ + ArcCurve: ArcCurve, + CatmullRomCurve3: CatmullRomCurve3, + CubicBezierCurve: CubicBezierCurve, + CubicBezierCurve3: CubicBezierCurve3, + EllipseCurve: EllipseCurve, + LineCurve: LineCurve, + LineCurve3: LineCurve3, + QuadraticBezierCurve: QuadraticBezierCurve, + QuadraticBezierCurve3: QuadraticBezierCurve3, + SplineCurve: SplineCurve + }); - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); + /** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + **/ - }, + /************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ - setInterpolation: function ( interpolation ) { + function CurvePath() { - var factoryMethod; + Curve.call( this ); - switch ( interpolation ) { + this.type = 'CurvePath'; - case InterpolateDiscrete: + this.curves = []; + this.autoClose = false; // Automatically closes the path - factoryMethod = this.InterpolantFactoryMethodDiscrete; + } - break; + CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { - case InterpolateLinear: + constructor: CurvePath, - factoryMethod = this.InterpolantFactoryMethodLinear; + add: function ( curve ) { - break; + this.curves.push( curve ); - case InterpolateSmooth: + }, - factoryMethod = this.InterpolantFactoryMethodSmooth; + closePath: function () { - break; + // Add a line curve if start and end of lines are not connected + var startPoint = this.curves[ 0 ].getPoint( 0 ); + var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); + + if ( ! startPoint.equals( endPoint ) ) { + + this.curves.push( new LineCurve( endPoint, startPoint ) ); } - if ( factoryMethod === undefined ) { + }, - var message = "unsupported interpolation for " + - this.ValueTypeName + " keyframe track named " + this.name; + // To get accurate point with reference to + // entire path distance at time t, + // following has to be done: - if ( this.createInterpolant === undefined ) { + // 1. Length of each sub path have to be known + // 2. Locate and identify type of curve + // 3. Get t for the curve + // 4. Return curve.getPointAt(t') - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { + getPoint: function ( t ) { - this.setInterpolation( this.DefaultInterpolation ); + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0; - } else { + // To think about boundaries points. - throw new Error( message ); // fatal, in this case + while ( i < curveLengths.length ) { - } + if ( curveLengths[ i ] >= d ) { + + var diff = curveLengths[ i ] - d; + var curve = this.curves[ i ]; + + var segmentLength = curve.getLength(); + var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + + return curve.getPointAt( u ); } - console.warn( 'THREE.KeyframeTrack:', message ); - return; + i ++; } - this.createInterpolant = factoryMethod; + return null; + + // loop where sum != 0, sum > d , sum+1 seconds conversions) - scale: function ( timeScale ) { + getPoints: function ( divisions ) { - if ( timeScale !== 1.0 ) { + divisions = divisions || 12; - var times = this.times; + var points = [], last; - for ( var i = 0, n = times.length; i !== n; ++ i ) { + for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) { - times[ i ] *= timeScale; + var curve = curves[ i ]; + var resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2 + : ( curve && curve.isLineCurve ) ? 1 + : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length + : divisions; - } + var pts = curve.getPoints( resolution ); - } + for ( var j = 0; j < pts.length; j ++ ) { - return this; + var point = pts[ j ]; - }, + if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates - // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. - // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values - trim: function ( startTime, endTime ) { + points.push( point ); + last = point; - var times = this.times, - nKeys = times.length, - from = 0, - to = nKeys - 1; + } - while ( from !== nKeys && times[ from ] < startTime ) { + } - ++ from; + if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { + + points.push( points[ 0 ] ); } - while ( to !== - 1 && times[ to ] > endTime ) { + return points; - -- to; + }, - } + copy: function ( source ) { - ++ to; // inclusive -> exclusive bound + Curve.prototype.copy.call( this, source ); - if ( from !== 0 || to !== nKeys ) { + this.curves = []; - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; + for ( var i = 0, l = source.curves.length; i < l; i ++ ) { - var stride = this.getValueSize(); - this.times = AnimationUtils.arraySlice( times, from, to ); - this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); + var curve = source.curves[ i ]; + + this.curves.push( curve.clone() ); } + this.autoClose = source.autoClose; + return this; }, - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate: function () { + toJSON: function () { - var valid = true; + var data = Curve.prototype.toJSON.call( this ); - var valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { + data.autoClose = this.autoClose; + data.curves = []; - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; + for ( var i = 0, l = this.curves.length; i < l; i ++ ) { + + var curve = this.curves[ i ]; + data.curves.push( curve.toJSON() ); } - var times = this.times, - values = this.values, + return data; - nKeys = times.length; + }, - if ( nKeys === 0 ) { + fromJSON: function ( json ) { - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; + Curve.prototype.fromJSON.call( this, json ); - } + this.autoClose = json.autoClose; + this.curves = []; - var prevTime = null; + for ( var i = 0, l = json.curves.length; i < l; i ++ ) { - for ( var i = 0; i !== nKeys; i ++ ) { + var curve = json.curves[ i ]; + this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); - var currTime = times[ i ]; + } - if ( typeof currTime === 'number' && isNaN( currTime ) ) { + return this; - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; + } - } + } ); - if ( prevTime !== null && prevTime > currTime ) { + /** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + **/ - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; + function Path( points ) { - } + CurvePath.call( this ); - prevTime = currTime; + this.type = 'Path'; - } + this.currentPoint = new Vector2(); - if ( values !== undefined ) { + if ( points ) { - if ( AnimationUtils.isTypedArray( values ) ) { + this.setFromPoints( points ); - for ( var i = 0, n = values.length; i !== n; ++ i ) { + } - var value = values[ i ]; + } - if ( isNaN( value ) ) { + Path.prototype = Object.assign( Object.create( CurvePath.prototype ), { - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; + constructor: Path, - } + setFromPoints: function ( points ) { - } + this.moveTo( points[ 0 ].x, points[ 0 ].y ); - } + for ( var i = 1, l = points.length; i < l; i ++ ) { + + this.lineTo( points[ i ].x, points[ i ].y ); } - return valid; + }, + + moveTo: function ( x, y ) { + + this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? }, - // removes equivalent sequential keys as common in morph target sequences - // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) - optimize: function () { + lineTo: function ( x, y ) { - var times = this.times, - values = this.values, - stride = this.getValueSize(), + var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); + this.curves.push( curve ); - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, + this.currentPoint.set( x, y ); - writeIndex = 1, - lastIndex = times.length - 1; + }, - for ( var i = 1; i < lastIndex; ++ i ) { + quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { - var keep = false; + var curve = new QuadraticBezierCurve( + this.currentPoint.clone(), + new Vector2( aCPx, aCPy ), + new Vector2( aX, aY ) + ); - var time = times[ i ]; - var timeNext = times[ i + 1 ]; + this.curves.push( curve ); - // remove adjacent keyframes scheduled at the same time + this.currentPoint.set( aX, aY ); - if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { + }, - if ( ! smoothInterpolation ) { + bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - // remove unnecessary keyframes same as their neighbors + var curve = new CubicBezierCurve( + this.currentPoint.clone(), + new Vector2( aCP1x, aCP1y ), + new Vector2( aCP2x, aCP2y ), + new Vector2( aX, aY ) + ); - var offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; + this.curves.push( curve ); - for ( var j = 0; j !== stride; ++ j ) { + this.currentPoint.set( aX, aY ); - var value = values[ offset + j ]; + }, - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { + splineThru: function ( pts /*Array of Vector*/ ) { - keep = true; - break; + var npts = [ this.currentPoint.clone() ].concat( pts ); - } + var curve = new SplineCurve( npts ); + this.curves.push( curve ); - } + this.currentPoint.copy( pts[ pts.length - 1 ] ); - } else { + }, - keep = true; + arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - } + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; - } + this.absarc( aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); - // in-place compaction + }, - if ( keep ) { + absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - if ( i !== writeIndex ) { + this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - times[ writeIndex ] = times[ i ]; + }, - var readOffset = i * stride, - writeOffset = writeIndex * stride; + ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - for ( var j = 0; j !== stride; ++ j ) { + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; - values[ writeOffset + j ] = values[ readOffset + j ]; + this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - } + }, - } + absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - ++ writeIndex; + var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + + if ( this.curves.length > 0 ) { + + // if a previous curve is present, attempt to join + var firstPoint = curve.getPoint( 0 ); + + if ( ! firstPoint.equals( this.currentPoint ) ) { + + this.lineTo( firstPoint.x, firstPoint.y ); } } - // flush last keyframe (compaction looks ahead) + this.curves.push( curve ); - if ( lastIndex > 0 ) { + var lastPoint = curve.getPoint( 1 ); + this.currentPoint.copy( lastPoint ); - times[ writeIndex ] = times[ lastIndex ]; + }, - for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { + copy: function ( source ) { - values[ writeOffset + j ] = values[ readOffset + j ]; + CurvePath.prototype.copy.call( this, source ); - } + this.currentPoint.copy( source.currentPoint ); - ++ writeIndex; + return this; - } + }, - if ( writeIndex !== times.length ) { + toJSON: function () { - this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); - this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); + var data = CurvePath.prototype.toJSON.call( this ); - } + data.currentPoint = this.currentPoint.toArray(); - return this; + return data; - } + }, - } ); + fromJSON: function ( json ) { - /** - * - * A Track of vectored keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - - function VectorKeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrack.call( this, name, times, values, interpolation ); - - } - - VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + CurvePath.prototype.fromJSON.call( this, json ); - constructor: VectorKeyframeTrack, - - ValueTypeName: 'vector' + this.currentPoint.fromArray( json.currentPoint ); - // ValueBufferType is inherited + return this; - // DefaultInterpolation is inherited + } } ); /** - * - * Reusable set of Tracks that represent an animation. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ - - function AnimationClip( name, duration, tracks ) { + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ - this.name = name; - this.tracks = tracks; - this.duration = ( duration !== undefined ) ? duration : - 1; + // STEP 1 Create a path. + // STEP 2 Turn path into shape. + // STEP 3 ExtrudeGeometry takes in Shape/Shapes + // STEP 3a - Extract points from each shape, turn to vertices + // STEP 3b - Triangulate each shape, add faces. - this.uuid = _Math.generateUUID(); + function Shape( points ) { - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { + Path.call( this, points ); - this.resetDuration(); + this.uuid = _Math.generateUUID(); - } + this.type = 'Shape'; - this.optimize(); + this.holes = []; } - Object.assign( AnimationClip, { + Shape.prototype = Object.assign( Object.create( Path.prototype ), { - parse: function ( json ) { + constructor: Shape, - var tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); + getPointsHoles: function ( divisions ) { - for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { + var holesPts = []; - tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) ); + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getPoints( divisions ); } - return new AnimationClip( json.name, json.duration, tracks ); + return holesPts; }, - toJSON: function ( clip ) { + // get points of shape and holes (keypoints based on segments parameter) - var tracks = [], - clipTracks = clip.tracks; + extractPoints: function ( divisions ) { - var json = { + return { - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks + shape: this.getPoints( divisions ), + holes: this.getPointsHoles( divisions ) }; - for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { - - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); + }, - } + copy: function ( source ) { - return json; + Path.prototype.copy.call( this, source ); - }, + this.holes = []; - CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { + for ( var i = 0, l = source.holes.length; i < l; i ++ ) { - var numMorphTargets = morphTargetSequence.length; - var tracks = []; + var hole = source.holes[ i ]; - for ( var i = 0; i < numMorphTargets; i ++ ) { + this.holes.push( hole.clone() ); - var times = []; - var values = []; + } - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); + return this; - values.push( 0, 1, 0 ); + }, - var order = AnimationUtils.getKeyframeOrder( times ); - times = AnimationUtils.sortedArray( times, 1, order ); - values = AnimationUtils.sortedArray( values, 1, order ); + toJSON: function () { - // if there is a key at the first frame, duplicate it as the - // last frame as well for perfect loop. - if ( ! noLoop && times[ 0 ] === 0 ) { + var data = Path.prototype.toJSON.call( this ); - times.push( numMorphTargets ); - values.push( values[ 0 ] ); + data.uuid = this.uuid; + data.holes = []; - } + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); + var hole = this.holes[ i ]; + data.holes.push( hole.toJSON() ); } - return new AnimationClip( name, - 1, tracks ); + return data; }, - findByName: function ( objectOrClipArray, name ) { + fromJSON: function ( json ) { - var clipArray = objectOrClipArray; + Path.prototype.fromJSON.call( this, json ); - if ( ! Array.isArray( objectOrClipArray ) ) { + this.uuid = json.uuid; + this.holes = []; - var o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; + for ( var i = 0, l = json.holes.length; i < l; i ++ ) { + + var hole = json.holes[ i ]; + this.holes.push( new Path().fromJSON( hole ) ); } - for ( var i = 0; i < clipArray.length; i ++ ) { + return this; - if ( clipArray[ i ].name === name ) { + } - return clipArray[ i ]; + } ); - } + /** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - } + function Light( color, intensity ) { - return null; + Object3D.call( this ); - }, + this.type = 'Light'; - CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { + this.color = new Color( color ); + this.intensity = intensity !== undefined ? intensity : 1; - var animationToMorphTargets = {}; + this.receiveShadow = undefined; - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - var pattern = /^([\w-]*?)([\d]+)$/; + } - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { + Light.prototype = Object.assign( Object.create( Object3D.prototype ), { - var morphTarget = morphTargets[ i ]; - var parts = morphTarget.name.match( pattern ); + constructor: Light, - if ( parts && parts.length > 1 ) { + isLight: true, - var name = parts[ 1 ]; + copy: function ( source ) { - var animationMorphTargets = animationToMorphTargets[ name ]; - if ( ! animationMorphTargets ) { + Object3D.prototype.copy.call( this, source ); - animationToMorphTargets[ name ] = animationMorphTargets = []; + this.color.copy( source.color ); + this.intensity = source.intensity; - } + return this; - animationMorphTargets.push( morphTarget ); + }, - } + toJSON: function ( meta ) { - } + var data = Object3D.prototype.toJSON.call( this, meta ); - var clips = []; + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; - for ( var name in animationToMorphTargets ) { + if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); - clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); + if ( this.distance !== undefined ) data.object.distance = this.distance; + if ( this.angle !== undefined ) data.object.angle = this.angle; + if ( this.decay !== undefined ) data.object.decay = this.decay; + if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; - } + if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); - return clips; + return data; - }, + } - // parse the animation.hierarchy format - parseAnimation: function ( animation, bones ) { + } ); - if ( ! animation ) { + /** + * @author alteredq / http://alteredqualia.com/ + */ - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; + function HemisphereLight( skyColor, groundColor, intensity ) { - } + Light.call( this, skyColor, intensity ); - var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { + this.type = 'HemisphereLight'; - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { + this.castShadow = undefined; - var times = []; - var values = []; + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); + this.groundColor = new Color( groundColor ); - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { + } - destTracks.push( new trackType( trackName, times, values ) ); + HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { - } + constructor: HemisphereLight, - } + isHemisphereLight: true, - }; + copy: function ( source ) { - var tracks = []; + Light.prototype.copy.call( this, source ); - var clipName = animation.name || 'default'; - // automatic length determination in AnimationClip. - var duration = animation.length || - 1; - var fps = animation.fps || 30; + this.groundColor.copy( source.groundColor ); - var hierarchyTracks = animation.hierarchy || []; + return this; - for ( var h = 0; h < hierarchyTracks.length; h ++ ) { + } - var animationKeys = hierarchyTracks[ h ].keys; + } ); - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; + /** + * @author mrdoob / http://mrdoob.com/ + */ - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { + function LightShadow( camera ) { - // figure out all morph targets used in this track - var morphTargetNames = {}; + this.camera = camera; - for ( var k = 0; k < animationKeys.length; k ++ ) { + this.bias = 0; + this.radius = 1; - if ( animationKeys[ k ].morphTargets ) { + this.mapSize = new Vector2( 512, 512 ); - for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { + this.map = null; + this.matrix = new Matrix4(); - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; + } - } + Object.assign( LightShadow.prototype, { - } + copy: function ( source ) { - } + this.camera = source.camera.clone(); - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( var morphTargetName in morphTargetNames ) { + this.bias = source.bias; + this.radius = source.radius; - var times = []; - var values = []; + this.mapSize.copy( source.mapSize ); - for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { + return this; - var animationKey = animationKeys[ k ]; + }, - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); + clone: function () { - } + return new this.constructor().copy( this ); - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); + }, - } + toJSON: function () { - duration = morphTargetNames.length * ( fps || 1.0 ); + var object = {}; - } else { + if ( this.bias !== 0 ) object.bias = this.bias; + if ( this.radius !== 1 ) object.radius = this.radius; + if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); - // ...assume skeletal animation + object.camera = this.camera.toJSON( false ).object; + delete object.camera.matrix; - var boneName = '.bones[' + bones[ h ].name + ']'; + return object; - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); + } - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); + } ); - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); + /** + * @author mrdoob / http://mrdoob.com/ + */ - } + function SpotLightShadow() { - } + LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - if ( tracks.length === 0 ) { + } - return null; + SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - } + constructor: SpotLightShadow, - var clip = new AnimationClip( clipName, duration, tracks ); + isSpotLightShadow: true, - return clip; + update: function ( light ) { + + var camera = this.camera; + + var fov = _Math.RAD2DEG * 2 * light.angle; + var aspect = this.mapSize.width / this.mapSize.height; + var far = light.distance || camera.far; + + if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + + camera.fov = fov; + camera.aspect = aspect; + camera.far = far; + camera.updateProjectionMatrix(); + + } } } ); - Object.assign( AnimationClip.prototype, { + /** + * @author alteredq / http://alteredqualia.com/ + */ - resetDuration: function () { + function SpotLight( color, intensity, distance, angle, penumbra, decay ) { - var tracks = this.tracks, duration = 0; + Light.call( this, color, intensity ); - for ( var i = 0, n = tracks.length; i !== n; ++ i ) { + this.type = 'SpotLight'; - var track = this.tracks[ i ]; + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); + this.target = new Object3D(); - } + Object.defineProperty( this, 'power', { + get: function () { - this.duration = duration; + // intensity = power per solid angle. + // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + return this.intensity * Math.PI; - }, + }, + set: function ( power ) { - trim: function () { + // intensity = power per solid angle. + // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + this.intensity = power / Math.PI; - for ( var i = 0; i < this.tracks.length; i ++ ) { + } + } ); - this.tracks[ i ].trim( 0, this.duration ); + this.distance = ( distance !== undefined ) ? distance : 0; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; + this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - } + this.shadow = new SpotLightShadow(); - return this; + } - }, + SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { - optimize: function () { + constructor: SpotLight, - for ( var i = 0; i < this.tracks.length; i ++ ) { + isSpotLight: true, - this.tracks[ i ].optimize(); + copy: function ( source ) { - } + Light.prototype.copy.call( this, source ); + + this.distance = source.distance; + this.angle = source.angle; + this.penumbra = source.penumbra; + this.decay = source.decay; + + this.target = source.target.clone(); + + this.shadow = source.shadow.clone(); return this; @@ -33475,3322 +33631,4046 @@ * @author mrdoob / http://mrdoob.com/ */ - function MaterialLoader( manager ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.textures = {}; + function PointLight( color, intensity, distance, decay ) { - } + Light.call( this, color, intensity ); - Object.assign( MaterialLoader.prototype, { + this.type = 'PointLight'; - load: function ( url, onLoad, onProgress, onError ) { + Object.defineProperty( this, 'power', { + get: function () { - var scope = this; + // intensity = power per solid angle. + // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + return this.intensity * 4 * Math.PI; - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + }, + set: function ( power ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + // intensity = power per solid angle. + // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + this.intensity = power / ( 4 * Math.PI ); - }, onProgress, onError ); + } + } ); - }, + this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - setTextures: function ( value ) { + this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - this.textures = value; + } - }, + PointLight.prototype = Object.assign( Object.create( Light.prototype ), { - parse: function ( json ) { + constructor: PointLight, - var textures = this.textures; + isPointLight: true, - function getTexture( name ) { + copy: function ( source ) { - if ( textures[ name ] === undefined ) { + Light.prototype.copy.call( this, source ); - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + this.distance = source.distance; + this.decay = source.decay; - } + this.shadow = source.shadow.clone(); - return textures[ name ]; + return this; - } + } - var material = new Materials[ json.type ](); + } ); - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; - if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; - if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.side !== undefined ) material.side = json.side; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; + /** + * @author mrdoob / http://mrdoob.com/ + */ - if ( json.rotation !== undefined ) material.rotation = json.rotation; + function DirectionalLightShadow( ) { - if ( json.linewidth !== 1 ) material.linewidth = json.linewidth; - if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; - if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; - if ( json.scale !== undefined ) material.scale = json.scale; + LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - if ( json.skinning !== undefined ) material.skinning = json.skinning; - if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; - if ( json.dithering !== undefined ) material.dithering = json.dithering; + } - if ( json.visible !== undefined ) material.visible = json.visible; - if ( json.userData !== undefined ) material.userData = json.userData; + DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - // Deprecated + constructor: DirectionalLightShadow - if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading + } ); - // for PointsMaterial + /** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + function DirectionalLight( color, intensity ) { - // maps + Light.call( this, color, intensity ); - if ( json.map !== undefined ) material.map = getTexture( json.map ); + this.type = 'DirectionalLight'; - if ( json.alphaMap !== undefined ) { + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - material.alphaMap = getTexture( json.alphaMap ); - material.transparent = true; + this.target = new Object3D(); - } + this.shadow = new DirectionalLightShadow(); - if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); - if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; + } - if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); - if ( json.normalScale !== undefined ) { + DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { - var normalScale = json.normalScale; + constructor: DirectionalLight, - if ( Array.isArray( normalScale ) === false ) { + isDirectionalLight: true, - // Blender exporter used to export a scalar. See #7459 + copy: function ( source ) { - normalScale = [ normalScale, normalScale ]; + Light.prototype.copy.call( this, source ); - } + this.target = source.target.clone(); - material.normalScale = new Vector2().fromArray( normalScale ); + this.shadow = source.shadow.clone(); - } + return this; - if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); - if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; - if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; + } - if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); - if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); + } ); - if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); - if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; + /** + * @author mrdoob / http://mrdoob.com/ + */ - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); + function AmbientLight( color, intensity ) { - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); + Light.call( this, color, intensity ); - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; + this.type = 'AmbientLight'; - if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); - if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; + this.castShadow = undefined; - if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); - if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; + } - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); + AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { - return material; + constructor: AmbientLight, + + isAmbientLight: true + + } ); + + /** + * @author abelnation / http://github.com/abelnation + */ + + function RectAreaLight( color, intensity, width, height ) { + + Light.call( this, color, intensity ); + + this.type = 'RectAreaLight'; + + this.position.set( 0, 1, 0 ); + this.updateMatrix(); + + this.width = ( width !== undefined ) ? width : 10; + this.height = ( height !== undefined ) ? height : 10; + + // TODO (abelnation): distance/decay + + // TODO (abelnation): update method for RectAreaLight to update transform to lookat target + + // TODO (abelnation): shadows + + } + + // TODO (abelnation): RectAreaLight update when light shape is changed + RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: RectAreaLight, + + isRectAreaLight: true, + + copy: function ( source ) { + + Light.prototype.copy.call( this, source ); + + this.width = source.width; + this.height = source.height; + + return this; + + }, + + toJSON: function ( meta ) { + + var data = Light.prototype.toJSON.call( this, meta ); + + data.object.width = this.width; + data.object.height = this.height; + + return data; } } ); /** - * @author mrdoob / http://mrdoob.com/ + * + * A Track that interpolates Strings + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw */ - function BufferGeometryLoader( manager ) { + function StringKeyframeTrack( name, times, values, interpolation ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + KeyframeTrack.call( this, name, times, values, interpolation ); } - Object.assign( BufferGeometryLoader.prototype, { + StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - load: function ( url, onLoad, onProgress, onError ) { + constructor: StringKeyframeTrack, - var scope = this; + ValueTypeName: 'string', + ValueBufferType: Array, - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + DefaultInterpolation: InterpolateDiscrete, - onLoad( scope.parse( JSON.parse( text ) ) ); + InterpolantFactoryMethodLinear: undefined, - }, onProgress, onError ); + InterpolantFactoryMethodSmooth: undefined + + } ); + + /** + * + * A Track of Boolean keyframe values. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + + function BooleanKeyframeTrack( name, times, values ) { + + KeyframeTrack.call( this, name, times, values ); + + } + + BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + + constructor: BooleanKeyframeTrack, + + ValueTypeName: 'bool', + ValueBufferType: Array, + + DefaultInterpolation: InterpolateDiscrete, + + InterpolantFactoryMethodLinear: undefined, + InterpolantFactoryMethodSmooth: undefined + + // Note: Actually this track could have a optimized / compressed + // representation of a single value and a custom interpolant that + // computes "firstValue ^ isOdd( index )". + + } ); + + /** + * Abstract base class of interpolants over parametric samples. + * + * The parameter domain is one dimensional, typically the time or a path + * along a curve defined by the data. + * + * The sample values can have any dimensionality and derived classes may + * apply special interpretations to the data. + * + * This class provides the interval seek in a Template Method, deferring + * the actual interpolation to derived classes. + * + * Time complexity is O(1) for linear access crossing at most two points + * and O(log N) for random access, where N is the number of positions. + * + * References: + * + * http://www.oodesign.com/template-method-pattern.html + * + * @author tschw + */ + + function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + this.parameterPositions = parameterPositions; + this._cachedIndex = 0; + + this.resultBuffer = resultBuffer !== undefined ? + resultBuffer : new sampleValues.constructor( sampleSize ); + this.sampleValues = sampleValues; + this.valueSize = sampleSize; + + } + + Object.assign( Interpolant.prototype, { + + evaluate: function ( t ) { + + var pp = this.parameterPositions, + i1 = this._cachedIndex, + + t1 = pp[ i1 ], + t0 = pp[ i1 - 1 ]; + + validate_interval: { + + seek: { + + var right; + + linear_scan: { + + //- See http://jsperf.com/comparison-to-undefined/3 + //- slower code: + //- + //- if ( t >= t1 || t1 === undefined ) { + forward_scan: if ( ! ( t < t1 ) ) { + + for ( var giveUpAt = i1 + 2; ; ) { + + if ( t1 === undefined ) { + + if ( t < t0 ) break forward_scan; + + // after end + + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t, t0 ); + + } + + if ( i1 === giveUpAt ) break; // this loop + + t0 = t1; + t1 = pp[ ++ i1 ]; + + if ( t < t1 ) { + + // we have arrived at the sought interval + break seek; + + } + + } + + // prepare binary search on the right side of the index + right = pp.length; + break linear_scan; + + } + + //- slower code: + //- if ( t < t0 || t0 === undefined ) { + if ( ! ( t >= t0 ) ) { + + // looping? + + var t1global = pp[ 1 ]; + + if ( t < t1global ) { + + i1 = 2; // + 1, using the scan for the details + t0 = t1global; + + } + + // linear reverse scan + + for ( var giveUpAt = i1 - 2; ; ) { + + if ( t0 === undefined ) { + + // before start + + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); + + } + + if ( i1 === giveUpAt ) break; // this loop + + t1 = t0; + t0 = pp[ -- i1 - 1 ]; + + if ( t >= t0 ) { + + // we have arrived at the sought interval + break seek; + + } + + } + + // prepare binary search on the left side of the index + right = i1; + i1 = 0; + break linear_scan; + + } + + // the interval is valid + + break validate_interval; + + } // linear scan + + // binary search + + while ( i1 < right ) { + + var mid = ( i1 + right ) >>> 1; + + if ( t < pp[ mid ] ) { + + right = mid; + + } else { + + i1 = mid + 1; + + } + + } + + t1 = pp[ i1 ]; + t0 = pp[ i1 - 1 ]; + + // check boundary cases, again + + if ( t0 === undefined ) { + + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); + + } + + if ( t1 === undefined ) { + + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t0, t ); + + } + + } // seek + + this._cachedIndex = i1; + + this.intervalChanged_( i1, t0, t1 ); + + } // validate_interval + + return this.interpolate_( i1, t0, t, t1 ); }, - parse: function ( json ) { + settings: null, // optional, subclass-specific settings structure + // Note: The indirection allows central control of many interpolants. - var geometry = new BufferGeometry(); + // --- Protected interface - var index = json.data.index; + DefaultSettings_: {}, - if ( index !== undefined ) { + getSettings_: function () { - var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); + return this.settings || this.DefaultSettings_; + + }, + + copySampleValue_: function ( index ) { + + // copies a sample value to the result buffer + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + offset = index * stride; + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = values[ offset + i ]; } - var attributes = json.data.attributes; + return result; - for ( var key in attributes ) { + }, - var attribute = attributes[ key ]; - var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); + // Template methods for derived classes: - geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); + interpolate_: function ( /* i1, t0, t, t1 */ ) { + + throw new Error( 'call to abstract method' ); + // implementations shall return this.resultBuffer + + }, + + intervalChanged_: function ( /* i1, t0, t1 */ ) { + + // empty + + } + + } ); + + //!\ DECLARE ALIAS AFTER assign prototype ! + Object.assign( Interpolant.prototype, { + + //( 0, t, t0 ), returns this.resultBuffer + beforeStart_: Interpolant.prototype.copySampleValue_, + + //( N-1, tN-1, t ), returns this.resultBuffer + afterEnd_: Interpolant.prototype.copySampleValue_, + + } ); + + /** + * Spherical linear unit quaternion interpolant. + * + * @author tschw + */ + + function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + + } + + QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + + constructor: QuaternionLinearInterpolant, + + interpolate_: function ( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + offset = i1 * stride, + + alpha = ( t - t0 ) / ( t1 - t0 ); + + for ( var end = offset + stride; offset !== end; offset += 4 ) { + + Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); } - var groups = json.data.groups || json.data.drawcalls || json.data.offsets; + return result; - if ( groups !== undefined ) { + } - for ( var i = 0, n = groups.length; i !== n; ++ i ) { + } ); - var group = groups[ i ]; + /** + * + * A Track of quaternion keyframe values. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - geometry.addGroup( group.start, group.count, group.materialIndex ); + function QuaternionKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrack.call( this, name, times, values, interpolation ); + + } + + QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + + constructor: QuaternionKeyframeTrack, + + ValueTypeName: 'quaternion', + + // ValueBufferType is inherited + + DefaultInterpolation: InterpolateLinear, + + InterpolantFactoryMethodLinear: function ( result ) { + + return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); + + }, + + InterpolantFactoryMethodSmooth: undefined // not yet implemented + + } ); + + /** + * + * A Track of keyframe values that represent color. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + + function ColorKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrack.call( this, name, times, values, interpolation ); + + } + + ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + + constructor: ColorKeyframeTrack, + + ValueTypeName: 'color' + + // ValueBufferType is inherited + + // DefaultInterpolation is inherited + + // Note: Very basic implementation and nothing special yet. + // However, this is the place for color space parameterization. + + } ); + + /** + * + * A Track of numeric keyframe values. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + + function NumberKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrack.call( this, name, times, values, interpolation ); + + } + + NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + + constructor: NumberKeyframeTrack, + + ValueTypeName: 'number' + + // ValueBufferType is inherited + + // DefaultInterpolation is inherited + + } ); + + /** + * Fast and simple cubic spline interpolant. + * + * It was derived from a Hermitian construction setting the first derivative + * at each sample position to the linear slope between neighboring positions + * over their parameter interval. + * + * @author tschw + */ + + function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + + this._weightPrev = - 0; + this._offsetPrev = - 0; + this._weightNext = - 0; + this._offsetNext = - 0; + + } + + CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + + constructor: CubicInterpolant, + + DefaultSettings_: { + + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + + }, + + intervalChanged_: function ( i1, t0, t1 ) { + + var pp = this.parameterPositions, + iPrev = i1 - 2, + iNext = i1 + 1, + + tPrev = pp[ iPrev ], + tNext = pp[ iNext ]; + + if ( tPrev === undefined ) { + + switch ( this.getSettings_().endingStart ) { + + case ZeroSlopeEnding: + + // f'(t0) = 0 + iPrev = i1; + tPrev = 2 * t0 - t1; + + break; + + case WrapAroundEnding: + + // use the other end of the curve + iPrev = pp.length - 2; + tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(t0) = 0 a.k.a. Natural Spline + iPrev = i1; + tPrev = t1; } } - var boundingSphere = json.data.boundingSphere; + if ( tNext === undefined ) { - if ( boundingSphere !== undefined ) { + switch ( this.getSettings_().endingEnd ) { - var center = new Vector3(); + case ZeroSlopeEnding: - if ( boundingSphere.center !== undefined ) { + // f'(tN) = 0 + iNext = i1; + tNext = 2 * t1 - t0; - center.fromArray( boundingSphere.center ); + break; + + case WrapAroundEnding: + + // use the other end of the curve + iNext = 1; + tNext = t1 + pp[ 1 ] - pp[ 0 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(tN) = 0, a.k.a. Natural Spline + iNext = i1 - 1; + tNext = t0; } - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); + } + + var halfDt = ( t1 - t0 ) * 0.5, + stride = this.valueSize; + + this._weightPrev = halfDt / ( t0 - tPrev ); + this._weightNext = halfDt / ( tNext - t1 ); + this._offsetPrev = iPrev * stride; + this._offsetNext = iNext * stride; + + }, + + interpolate_: function ( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + o1 = i1 * stride, o0 = o1 - stride, + oP = this._offsetPrev, oN = this._offsetNext, + wP = this._weightPrev, wN = this._weightNext, + + p = ( t - t0 ) / ( t1 - t0 ), + pp = p * p, + ppp = pp * p; + + // evaluate polynomials + + var sP = - wP * ppp + 2 * wP * pp - wP * p; + var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; + var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; + var sN = wN * ppp - wN * pp; + + // combine data linearly + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = + sP * values[ oP + i ] + + s0 * values[ o0 + i ] + + s1 * values[ o1 + i ] + + sN * values[ oN + i ]; } - return geometry; + return result; } } ); - var TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - // Workaround for IE11 pre KB2929437. See #11440 - Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array - }; + /** + * @author tschw + */ + + function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + + } + + LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + + constructor: LinearInterpolant, + + interpolate_: function ( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + offset1 = i1 * stride, + offset0 = offset1 - stride, + + weight1 = ( t - t0 ) / ( t1 - t0 ), + weight0 = 1 - weight1; + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = + values[ offset0 + i ] * weight0 + + values[ offset1 + i ] * weight1; + + } + + return result; + + } + + } ); /** - * @author alteredq / http://alteredqualia.com/ + * + * Interpolant that evaluates to the sample value at the position preceeding + * the parameter. + * + * @author tschw */ - function Loader() { + function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - this.onLoadStart = function () {}; - this.onLoadProgress = function () {}; - this.onLoadComplete = function () {}; + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); } - Loader.Handlers = { + DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - handlers: [], + constructor: DiscreteInterpolant, - add: function ( regex, loader ) { + interpolate_: function ( i1 /*, t0, t, t1 */ ) { - this.handlers.push( regex, loader ); + return this.copySampleValue_( i1 - 1 ); + + } + + } ); + + /** + * @author tschw + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ + + var AnimationUtils = { + + // same as Array.prototype.slice, but also works on typed arrays + arraySlice: function ( array, from, to ) { + + if ( AnimationUtils.isTypedArray( array ) ) { + + // in ios9 array.subarray(from, undefined) will return empty array + // but array.subarray(from) or array.subarray(from, len) is correct + return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) ); + + } + + return array.slice( from, to ); }, - get: function ( file ) { + // converts an array to a specific type + convertArray: function ( array, type, forceClone ) { + + if ( ! array || // let 'undefined' and 'null' pass + ! forceClone && array.constructor === type ) return array; + + if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + + return new type( array ); // create typed array + + } + + return Array.prototype.slice.call( array ); // create Array + + }, + + isTypedArray: function ( object ) { + + return ArrayBuffer.isView( object ) && + ! ( object instanceof DataView ); + + }, + + // returns an array by which times and values can be sorted + getKeyframeOrder: function ( times ) { + + function compareTime( i, j ) { + + return times[ i ] - times[ j ]; + + } + + var n = times.length; + var result = new Array( n ); + for ( var i = 0; i !== n; ++ i ) result[ i ] = i; + + result.sort( compareTime ); + + return result; + + }, + + // uses the array previously returned by 'getKeyframeOrder' to sort data + sortedArray: function ( values, stride, order ) { + + var nValues = values.length; + var result = new values.constructor( nValues ); + + for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + + var srcOffset = order[ i ] * stride; + + for ( var j = 0; j !== stride; ++ j ) { + + result[ dstOffset ++ ] = values[ srcOffset + j ]; + + } + + } + + return result; + + }, + + // function for parsing AOS keyframe formats + flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { + + var i = 1, key = jsonKeys[ 0 ]; + + while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + + key = jsonKeys[ i ++ ]; + + } + + if ( key === undefined ) return; // no data + + var value = key[ valuePropertyName ]; + if ( value === undefined ) return; // no data + + if ( Array.isArray( value ) ) { + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + values.push.apply( values, value ); // push all elements + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } else if ( value.toArray !== undefined ) { + + // ...assume THREE.Math-ish + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + value.toArray( values, values.length ); + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } else { + + // otherwise push as-is + + do { - var handlers = this.handlers; + value = key[ valuePropertyName ]; - for ( var i = 0, l = handlers.length; i < l; i += 2 ) { + if ( value !== undefined ) { - var regex = handlers[ i ]; - var loader = handlers[ i + 1 ]; + times.push( key.time ); + values.push( value ); - if ( regex.test( file ) ) { + } - return loader; + key = jsonKeys[ i ++ ]; - } + } while ( key !== undefined ); } - return null; - } }; - Object.assign( Loader.prototype, { - - crossOrigin: undefined, + /** + * + * A timed sequence of keyframes for a specific property. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - initMaterials: function ( materials, texturePath, crossOrigin ) { + function KeyframeTrack( name, times, values, interpolation ) { - var array = []; + if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); + if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); - for ( var i = 0; i < materials.length; ++ i ) { + this.name = name; - array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); + this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); + this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); - } + this.setInterpolation( interpolation || this.DefaultInterpolation ); - return array; + this.validate(); + this.optimize(); - }, + } - createMaterial: ( function () { + // Static methods: - var BlendingMode = { - NoBlending: NoBlending, - NormalBlending: NormalBlending, - AdditiveBlending: AdditiveBlending, - SubtractiveBlending: SubtractiveBlending, - MultiplyBlending: MultiplyBlending, - CustomBlending: CustomBlending - }; + Object.assign( KeyframeTrack, { - var color = new Color(); - var textureLoader = new TextureLoader(); - var materialLoader = new MaterialLoader(); + // Serialization (in static context, because of constructor invocation + // and automatic invocation of .toJSON): - return function createMaterial( m, texturePath, crossOrigin ) { + parse: function ( json ) { - // convert from old material format + if ( json.type === undefined ) { - var textures = {}; + throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); - function loadTexture( path, repeat, offset, wrap, anisotropy ) { + } - var fullPath = texturePath + path; - var loader = Loader.Handlers.get( fullPath ); + var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type ); - var texture; + if ( json.times === undefined ) { - if ( loader !== null ) { + var times = [], values = []; - texture = loader.load( fullPath ); + AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); - } else { + json.times = times; + json.values = values; - textureLoader.setCrossOrigin( crossOrigin ); - texture = textureLoader.load( fullPath ); + } - } + // derived classes can define a static parse method + if ( trackType.parse !== undefined ) { - if ( repeat !== undefined ) { + return trackType.parse( json ); - texture.repeat.fromArray( repeat ); + } else { - if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; + // by default, we assume a constructor compatible with the base + return new trackType( json.name, json.times, json.values, json.interpolation ); - } + } - if ( offset !== undefined ) { + }, - texture.offset.fromArray( offset ); + toJSON: function ( track ) { - } + var trackType = track.constructor; - if ( wrap !== undefined ) { + var json; - if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; - if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; + // derived classes can define a static toJSON method + if ( trackType.toJSON !== undefined ) { - if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; - if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; + json = trackType.toJSON( track ); - } + } else { - if ( anisotropy !== undefined ) { + // by default, we assume the data can be serialized as-is + json = { - texture.anisotropy = anisotropy; + 'name': track.name, + 'times': AnimationUtils.convertArray( track.times, Array ), + 'values': AnimationUtils.convertArray( track.values, Array ) - } + }; - var uuid = _Math.generateUUID(); + var interpolation = track.getInterpolation(); - textures[ uuid ] = texture; + if ( interpolation !== track.DefaultInterpolation ) { - return uuid; + json.interpolation = interpolation; } - // - - var json = { - uuid: _Math.generateUUID(), - type: 'MeshLambertMaterial' - }; - - for ( var name in m ) { + } - var value = m[ name ]; + json.type = track.ValueTypeName; // mandatory - switch ( name ) { + return json; - case 'DbgColor': - case 'DbgIndex': - case 'opticalDensity': - case 'illumination': - break; - case 'DbgName': - json.name = value; - break; - case 'blending': - json.blending = BlendingMode[ value ]; - break; - case 'colorAmbient': - case 'mapAmbient': - console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); - break; - case 'colorDiffuse': - json.color = color.fromArray( value ).getHex(); - break; - case 'colorSpecular': - json.specular = color.fromArray( value ).getHex(); - break; - case 'colorEmissive': - json.emissive = color.fromArray( value ).getHex(); - break; - case 'specularCoef': - json.shininess = value; - break; - case 'shading': - if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; - if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; - if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; - break; - case 'mapDiffuse': - json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - break; - case 'mapDiffuseRepeat': - case 'mapDiffuseOffset': - case 'mapDiffuseWrap': - case 'mapDiffuseAnisotropy': - break; - case 'mapEmissive': - json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); - break; - case 'mapEmissiveRepeat': - case 'mapEmissiveOffset': - case 'mapEmissiveWrap': - case 'mapEmissiveAnisotropy': - break; - case 'mapLight': - json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - break; - case 'mapLightRepeat': - case 'mapLightOffset': - case 'mapLightWrap': - case 'mapLightAnisotropy': - break; - case 'mapAO': - json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); - break; - case 'mapAORepeat': - case 'mapAOOffset': - case 'mapAOWrap': - case 'mapAOAnisotropy': - break; - case 'mapBump': - json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - break; - case 'mapBumpScale': - json.bumpScale = value; - break; - case 'mapBumpRepeat': - case 'mapBumpOffset': - case 'mapBumpWrap': - case 'mapBumpAnisotropy': - break; - case 'mapNormal': - json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - break; - case 'mapNormalFactor': - json.normalScale = [ value, value ]; - break; - case 'mapNormalRepeat': - case 'mapNormalOffset': - case 'mapNormalWrap': - case 'mapNormalAnisotropy': - break; - case 'mapSpecular': - json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - break; - case 'mapSpecularRepeat': - case 'mapSpecularOffset': - case 'mapSpecularWrap': - case 'mapSpecularAnisotropy': - break; - case 'mapMetalness': - json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); - break; - case 'mapMetalnessRepeat': - case 'mapMetalnessOffset': - case 'mapMetalnessWrap': - case 'mapMetalnessAnisotropy': - break; - case 'mapRoughness': - json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); - break; - case 'mapRoughnessRepeat': - case 'mapRoughnessOffset': - case 'mapRoughnessWrap': - case 'mapRoughnessAnisotropy': - break; - case 'mapAlpha': - json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - break; - case 'mapAlphaRepeat': - case 'mapAlphaOffset': - case 'mapAlphaWrap': - case 'mapAlphaAnisotropy': - break; - case 'flipSided': - json.side = BackSide; - break; - case 'doubleSided': - json.side = DoubleSide; - break; - case 'transparency': - console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); - json.opacity = value; - break; - case 'depthTest': - case 'depthWrite': - case 'colorWrite': - case 'opacity': - case 'reflectivity': - case 'transparent': - case 'visible': - case 'wireframe': - json[ name ] = value; - break; - case 'vertexColors': - if ( value === true ) json.vertexColors = VertexColors; - if ( value === 'face' ) json.vertexColors = FaceColors; - break; - default: - console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); - break; + }, - } + _getTrackTypeForValueTypeName: function ( typeName ) { - } + switch ( typeName.toLowerCase() ) { - if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; - if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; + case 'scalar': + case 'double': + case 'float': + case 'number': + case 'integer': - if ( json.opacity < 1 ) json.transparent = true; + return NumberKeyframeTrack; - materialLoader.setTextures( textures ); + case 'vector': + case 'vector2': + case 'vector3': + case 'vector4': - return materialLoader.parse( json ); + return VectorKeyframeTrack; - }; + case 'color': - } )() + return ColorKeyframeTrack; - } ); + case 'quaternion': - /** - * @author Don McCurdy / https://www.donmccurdy.com - */ + return QuaternionKeyframeTrack; - var LoaderUtils = { + case 'bool': + case 'boolean': - decodeText: function ( array ) { + return BooleanKeyframeTrack; - if ( typeof TextDecoder !== 'undefined' ) { + case 'string': - return new TextDecoder().decode( array ); + return StringKeyframeTrack; } - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. + throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - var s = ''; + } - for ( var i = 0, il = array.length; i < il; i ++ ) { + } ); - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); + Object.assign( KeyframeTrack.prototype, { - } + constructor: KeyframeTrack, - return s; + TimeBufferType: Float32Array, - }, + ValueBufferType: Float32Array, - extractUrlBase: function ( url ) { + DefaultInterpolation: InterpolateLinear, - var parts = url.split( '/' ); + InterpolantFactoryMethodDiscrete: function ( result ) { - if ( parts.length === 1 ) return './'; + return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); - parts.pop(); + }, - return parts.join( '/' ) + '/'; + InterpolantFactoryMethodLinear: function ( result ) { - } + return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); - }; + }, - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + InterpolantFactoryMethodSmooth: function ( result ) { - function JSONLoader( manager ) { + return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); - if ( typeof manager === 'boolean' ) { + }, - console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); - manager = undefined; + setInterpolation: function ( interpolation ) { - } + var factoryMethod; - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + switch ( interpolation ) { - this.withCredentials = false; + case InterpolateDiscrete: - } + factoryMethod = this.InterpolantFactoryMethodDiscrete; - Object.assign( JSONLoader.prototype, { + break; - load: function ( url, onLoad, onProgress, onError ) { + case InterpolateLinear: - var scope = this; + factoryMethod = this.InterpolantFactoryMethodLinear; - var texturePath = this.texturePath && ( typeof this.texturePath === 'string' ) ? this.texturePath : LoaderUtils.extractUrlBase( url ); + break; - var loader = new FileLoader( this.manager ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { + case InterpolateSmooth: - var json = JSON.parse( text ); - var metadata = json.metadata; + factoryMethod = this.InterpolantFactoryMethodSmooth; - if ( metadata !== undefined ) { + break; - var type = metadata.type; + } - if ( type !== undefined ) { + if ( factoryMethod === undefined ) { - if ( type.toLowerCase() === 'object' ) { + var message = "unsupported interpolation for " + + this.ValueTypeName + " keyframe track named " + this.name; - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); - return; + if ( this.createInterpolant === undefined ) { - } + // fall back to default, unless the default itself is messed up + if ( interpolation !== this.DefaultInterpolation ) { - if ( type.toLowerCase() === 'scene' ) { + this.setInterpolation( this.DefaultInterpolation ); - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); - return; + } else { - } + throw new Error( message ); // fatal, in this case } } - var object = scope.parse( json, texturePath ); - onLoad( object.geometry, object.materials ); - - }, onProgress, onError ); - - }, + console.warn( 'THREE.KeyframeTrack:', message ); + return; - setTexturePath: function ( value ) { + } - this.texturePath = value; + this.createInterpolant = factoryMethod; }, - parse: ( function () { - - function parseModel( json, geometry ) { - - function isBitSet( value, position ) { + getInterpolation: function () { - return value & ( 1 << position ); + switch ( this.createInterpolant ) { - } + case this.InterpolantFactoryMethodDiscrete: - var i, j, fi, + return InterpolateDiscrete; - offset, zLength, + case this.InterpolantFactoryMethodLinear: - colorIndex, normalIndex, uvIndex, materialIndex, + return InterpolateLinear; - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, + case this.InterpolantFactoryMethodSmooth: - vertex, face, faceA, faceB, hex, normal, + return InterpolateSmooth; - uvLayer, uv, u, v, + } - faces = json.faces, - vertices = json.vertices, - normals = json.normals, - colors = json.colors, + }, - scale = json.scale, + getValueSize: function () { - nUvLayers = 0; + return this.values.length / this.times.length; + }, - if ( json.uvs !== undefined ) { + // move all keyframes either forwards or backwards in time + shift: function ( timeOffset ) { - // disregard empty arrays + if ( timeOffset !== 0.0 ) { - for ( i = 0; i < json.uvs.length; i ++ ) { + var times = this.times; - if ( json.uvs[ i ].length ) nUvLayers ++; + for ( var i = 0, n = times.length; i !== n; ++ i ) { - } + times[ i ] += timeOffset; - for ( i = 0; i < nUvLayers; i ++ ) { + } - geometry.faceVertexUvs[ i ] = []; + } - } + return this; - } + }, - offset = 0; - zLength = vertices.length; + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale: function ( timeScale ) { - while ( offset < zLength ) { + if ( timeScale !== 1.0 ) { - vertex = new Vector3(); + var times = this.times; - vertex.x = vertices[ offset ++ ] * scale; - vertex.y = vertices[ offset ++ ] * scale; - vertex.z = vertices[ offset ++ ] * scale; + for ( var i = 0, n = times.length; i !== n; ++ i ) { - geometry.vertices.push( vertex ); + times[ i ] *= timeScale; } - offset = 0; - zLength = faces.length; - - while ( offset < zLength ) { - - type = faces[ offset ++ ]; + } - isQuad = isBitSet( type, 0 ); - hasMaterial = isBitSet( type, 1 ); - hasFaceVertexUv = isBitSet( type, 3 ); - hasFaceNormal = isBitSet( type, 4 ); - hasFaceVertexNormal = isBitSet( type, 5 ); - hasFaceColor = isBitSet( type, 6 ); - hasFaceVertexColor = isBitSet( type, 7 ); + return this; - // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); + }, - if ( isQuad ) { + // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. + // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values + trim: function ( startTime, endTime ) { - faceA = new Face3(); - faceA.a = faces[ offset ]; - faceA.b = faces[ offset + 1 ]; - faceA.c = faces[ offset + 3 ]; + var times = this.times, + nKeys = times.length, + from = 0, + to = nKeys - 1; - faceB = new Face3(); - faceB.a = faces[ offset + 1 ]; - faceB.b = faces[ offset + 2 ]; - faceB.c = faces[ offset + 3 ]; + while ( from !== nKeys && times[ from ] < startTime ) { - offset += 4; + ++ from; - if ( hasMaterial ) { + } - materialIndex = faces[ offset ++ ]; - faceA.materialIndex = materialIndex; - faceB.materialIndex = materialIndex; + while ( to !== - 1 && times[ to ] > endTime ) { - } + -- to; - // to get face <=> uv index correspondence + } - fi = geometry.faces.length; + ++ to; // inclusive -> exclusive bound - if ( hasFaceVertexUv ) { + if ( from !== 0 || to !== nKeys ) { - for ( i = 0; i < nUvLayers; i ++ ) { + // empty tracks are forbidden, so keep at least one keyframe + if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; - uvLayer = json.uvs[ i ]; + var stride = this.getValueSize(); + this.times = AnimationUtils.arraySlice( times, from, to ); + this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); - geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi + 1 ] = []; + } - for ( j = 0; j < 4; j ++ ) { + return this; - uvIndex = faces[ offset ++ ]; + }, - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable + validate: function () { - uv = new Vector2( u, v ); + var valid = true; - if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); - if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); + var valueSize = this.getValueSize(); + if ( valueSize - Math.floor( valueSize ) !== 0 ) { - } + console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); + valid = false; - } + } - } + var times = this.times, + values = this.values, - if ( hasFaceNormal ) { + nKeys = times.length; - normalIndex = faces[ offset ++ ] * 3; + if ( nKeys === 0 ) { - faceA.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + console.error( 'THREE.KeyframeTrack: Track is empty.', this ); + valid = false; - faceB.normal.copy( faceA.normal ); + } - } + var prevTime = null; - if ( hasFaceVertexNormal ) { + for ( var i = 0; i !== nKeys; i ++ ) { - for ( i = 0; i < 4; i ++ ) { + var currTime = times[ i ]; - normalIndex = faces[ offset ++ ] * 3; + if ( typeof currTime === 'number' && isNaN( currTime ) ) { - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); + valid = false; + break; + } - if ( i !== 2 ) faceA.vertexNormals.push( normal ); - if ( i !== 0 ) faceB.vertexNormals.push( normal ); + if ( prevTime !== null && prevTime > currTime ) { - } + console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); + valid = false; + break; - } + } + prevTime = currTime; - if ( hasFaceColor ) { + } - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + if ( values !== undefined ) { - faceA.color.setHex( hex ); - faceB.color.setHex( hex ); + if ( AnimationUtils.isTypedArray( values ) ) { - } + for ( var i = 0, n = values.length; i !== n; ++ i ) { + var value = values[ i ]; - if ( hasFaceVertexColor ) { + if ( isNaN( value ) ) { - for ( i = 0; i < 4; i ++ ) { + console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); + valid = false; + break; - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + } - if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); + } - } + } - } + } - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); + return valid; - } else { + }, - face = new Face3(); - face.a = faces[ offset ++ ]; - face.b = faces[ offset ++ ]; - face.c = faces[ offset ++ ]; + // removes equivalent sequential keys as common in morph target sequences + // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) + optimize: function () { - if ( hasMaterial ) { + var times = this.times, + values = this.values, + stride = this.getValueSize(), - materialIndex = faces[ offset ++ ]; - face.materialIndex = materialIndex; + smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - } + writeIndex = 1, + lastIndex = times.length - 1; - // to get face <=> uv index correspondence + for ( var i = 1; i < lastIndex; ++ i ) { - fi = geometry.faces.length; + var keep = false; - if ( hasFaceVertexUv ) { + var time = times[ i ]; + var timeNext = times[ i + 1 ]; - for ( i = 0; i < nUvLayers; i ++ ) { + // remove adjacent keyframes scheduled at the same time - uvLayer = json.uvs[ i ]; + if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { - geometry.faceVertexUvs[ i ][ fi ] = []; + if ( ! smoothInterpolation ) { - for ( j = 0; j < 3; j ++ ) { + // remove unnecessary keyframes same as their neighbors - uvIndex = faces[ offset ++ ]; + var offset = i * stride, + offsetP = offset - stride, + offsetN = offset + stride; - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + for ( var j = 0; j !== stride; ++ j ) { - uv = new Vector2( u, v ); + var value = values[ offset + j ]; - geometry.faceVertexUvs[ i ][ fi ].push( uv ); + if ( value !== values[ offsetP + j ] || + value !== values[ offsetN + j ] ) { - } + keep = true; + break; } } - if ( hasFaceNormal ) { + } else { - normalIndex = faces[ offset ++ ] * 3; + keep = true; - face.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + } - } + } - if ( hasFaceVertexNormal ) { + // in-place compaction - for ( i = 0; i < 3; i ++ ) { + if ( keep ) { - normalIndex = faces[ offset ++ ] * 3; + if ( i !== writeIndex ) { - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + times[ writeIndex ] = times[ i ]; - face.vertexNormals.push( normal ); + var readOffset = i * stride, + writeOffset = writeIndex * stride; - } + for ( var j = 0; j !== stride; ++ j ) { + + values[ writeOffset + j ] = values[ readOffset + j ]; } + } - if ( hasFaceColor ) { + ++ writeIndex; - colorIndex = faces[ offset ++ ]; - face.color.setHex( colors[ colorIndex ] ); + } - } + } + // flush last keyframe (compaction looks ahead) - if ( hasFaceVertexColor ) { + if ( lastIndex > 0 ) { - for ( i = 0; i < 3; i ++ ) { + times[ writeIndex ] = times[ lastIndex ]; - colorIndex = faces[ offset ++ ]; - face.vertexColors.push( new Color( colors[ colorIndex ] ) ); + for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { - } + values[ writeOffset + j ] = values[ readOffset + j ]; - } + } - geometry.faces.push( face ); + ++ writeIndex; - } + } - } + if ( writeIndex !== times.length ) { - } + this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); + this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); - function parseSkin( json, geometry ) { + } - var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; + return this; - if ( json.skinWeights ) { + } - for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { + } ); - var x = json.skinWeights[ i ]; - var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; - var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; - var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; + /** + * + * A Track of vectored keyframe values. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - geometry.skinWeights.push( new Vector4( x, y, z, w ) ); + function VectorKeyframeTrack( name, times, values, interpolation ) { - } + KeyframeTrack.call( this, name, times, values, interpolation ); - } + } - if ( json.skinIndices ) { + VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { + constructor: VectorKeyframeTrack, - var a = json.skinIndices[ i ]; - var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; - var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; - var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; + ValueTypeName: 'vector' - geometry.skinIndices.push( new Vector4( a, b, c, d ) ); + // ValueBufferType is inherited - } + // DefaultInterpolation is inherited - } + } ); - geometry.bones = json.bones; + /** + * + * Reusable set of Tracks that represent an animation. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { + function AnimationClip( name, duration, tracks ) { - console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); + this.name = name; + this.tracks = tracks; + this.duration = ( duration !== undefined ) ? duration : - 1; - } + this.uuid = _Math.generateUUID(); - } + // this means it should figure out its duration by scanning the tracks + if ( this.duration < 0 ) { - function parseMorphing( json, geometry ) { + this.resetDuration(); - var scale = json.scale; + } - if ( json.morphTargets !== undefined ) { + this.optimize(); - for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { + } - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; + Object.assign( AnimationClip, { - var dstVertices = geometry.morphTargets[ i ].vertices; - var srcVertices = json.morphTargets[ i ].vertices; + parse: function ( json ) { - for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + var tracks = [], + jsonTracks = json.tracks, + frameTime = 1.0 / ( json.fps || 1.0 ); - var vertex = new Vector3(); - vertex.x = srcVertices[ v ] * scale; - vertex.y = srcVertices[ v + 1 ] * scale; - vertex.z = srcVertices[ v + 2 ] * scale; + for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { - dstVertices.push( vertex ); + tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) ); - } + } - } + return new AnimationClip( json.name, json.duration, tracks ); - } + }, - if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { + toJSON: function ( clip ) { - console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); + var tracks = [], + clipTracks = clip.tracks; - var faces = geometry.faces; - var morphColors = json.morphColors[ 0 ].colors; + var json = { - for ( var i = 0, l = faces.length; i < l; i ++ ) { + 'name': clip.name, + 'duration': clip.duration, + 'tracks': tracks - faces[ i ].color.fromArray( morphColors, i * 3 ); + }; - } + for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { - } + tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); } - function parseAnimations( json, geometry ) { - - var outputAnimations = []; + return json; - // parse old style Bone/Hierarchy animations - var animations = []; + }, - if ( json.animation !== undefined ) { + CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { - animations.push( json.animation ); + var numMorphTargets = morphTargetSequence.length; + var tracks = []; - } + for ( var i = 0; i < numMorphTargets; i ++ ) { - if ( json.animations !== undefined ) { + var times = []; + var values = []; - if ( json.animations.length ) { + times.push( + ( i + numMorphTargets - 1 ) % numMorphTargets, + i, + ( i + 1 ) % numMorphTargets ); - animations = animations.concat( json.animations ); + values.push( 0, 1, 0 ); - } else { + var order = AnimationUtils.getKeyframeOrder( times ); + times = AnimationUtils.sortedArray( times, 1, order ); + values = AnimationUtils.sortedArray( values, 1, order ); - animations.push( json.animations ); + // if there is a key at the first frame, duplicate it as the + // last frame as well for perfect loop. + if ( ! noLoop && times[ 0 ] === 0 ) { - } + times.push( numMorphTargets ); + values.push( values[ 0 ] ); } - for ( var i = 0; i < animations.length; i ++ ) { + tracks.push( + new NumberKeyframeTrack( + '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', + times, values + ).scale( 1.0 / fps ) ); - var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); - if ( clip ) outputAnimations.push( clip ); + } - } + return new AnimationClip( name, - 1, tracks ); - // parse implicit morph animations - if ( geometry.morphTargets ) { + }, - // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. - var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); - outputAnimations = outputAnimations.concat( morphAnimationClips ); + findByName: function ( objectOrClipArray, name ) { - } + var clipArray = objectOrClipArray; - if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; + if ( ! Array.isArray( objectOrClipArray ) ) { + + var o = objectOrClipArray; + clipArray = o.geometry && o.geometry.animations || o.animations; } - return function ( json, texturePath ) { + for ( var i = 0; i < clipArray.length; i ++ ) { - if ( json.data !== undefined ) { + if ( clipArray[ i ].name === name ) { - // Geometry 4.0 spec - json = json.data; + return clipArray[ i ]; } - if ( json.scale !== undefined ) { + } - json.scale = 1.0 / json.scale; + return null; - } else { + }, - json.scale = 1.0; + CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { - } + var animationToMorphTargets = {}; - var geometry = new Geometry(); + // tested with https://regex101.com/ on trick sequences + // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + var pattern = /^([\w-]*?)([\d]+)$/; - parseModel( json, geometry ); - parseSkin( json, geometry ); - parseMorphing( json, geometry ); - parseAnimations( json, geometry ); + // sort morph target names into animation groups based + // patterns like Walk_001, Walk_002, Run_001, Run_002 + for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); + var morphTarget = morphTargets[ i ]; + var parts = morphTarget.name.match( pattern ); - if ( json.materials === undefined || json.materials.length === 0 ) { + if ( parts && parts.length > 1 ) { - return { geometry: geometry }; + var name = parts[ 1 ]; - } else { + var animationMorphTargets = animationToMorphTargets[ name ]; + if ( ! animationMorphTargets ) { - var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); + animationToMorphTargets[ name ] = animationMorphTargets = []; - return { geometry: geometry, materials: materials }; + } - } + animationMorphTargets.push( morphTarget ); - }; + } - } )() + } - } ); + var clips = []; - /** - * @author mrdoob / http://mrdoob.com/ - */ + for ( var name in animationToMorphTargets ) { - function ObjectLoader( manager ) { + clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.texturePath = ''; + } - } + return clips; - Object.assign( ObjectLoader.prototype, { + }, - load: function ( url, onLoad, onProgress, onError ) { + // parse the animation.hierarchy format + parseAnimation: function ( animation, bones ) { - if ( this.texturePath === '' ) { + if ( ! animation ) { - this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); + console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); + return null; } - var scope = this; + var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + // only return track if there are actually keys. + if ( animationKeys.length !== 0 ) { + + var times = []; + var values = []; + + AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); + + // empty keys are filtered out, so check again + if ( times.length !== 0 ) { + + destTracks.push( new trackType( trackName, times, values ) ); + + } + + } + + }; - var json = null; + var tracks = []; - try { + var clipName = animation.name || 'default'; + // automatic length determination in AnimationClip. + var duration = animation.length || - 1; + var fps = animation.fps || 30; - json = JSON.parse( text ); + var hierarchyTracks = animation.hierarchy || []; - } catch ( error ) { + for ( var h = 0; h < hierarchyTracks.length; h ++ ) { - if ( onError !== undefined ) onError( error ); + var animationKeys = hierarchyTracks[ h ].keys; - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); + // skip empty tracks + if ( ! animationKeys || animationKeys.length === 0 ) continue; - return; + // process morph targets + if ( animationKeys[ 0 ].morphTargets ) { - } + // figure out all morph targets used in this track + var morphTargetNames = {}; - var metadata = json.metadata; + for ( var k = 0; k < animationKeys.length; k ++ ) { - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + if ( animationKeys[ k ].morphTargets ) { - console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); - return; + for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - } + morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - scope.parse( json, onLoad ); + } - }, onProgress, onError ); + } - }, + } - setTexturePath: function ( value ) { + // create a track for each morph target with all zero + // morphTargetInfluences except for the keys in which + // the morphTarget is named. + for ( var morphTargetName in morphTargetNames ) { - this.texturePath = value; + var times = []; + var values = []; - }, + for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - setCrossOrigin: function ( value ) { + var animationKey = animationKeys[ k ]; - this.crossOrigin = value; + times.push( animationKey.time ); + values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - }, + } - parse: function ( json, onLoad ) { + tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - var geometries = this.parseGeometries( json.geometries ); + } - var images = this.parseImages( json.images, function () { + duration = morphTargetNames.length * ( fps || 1.0 ); - if ( onLoad !== undefined ) onLoad( object ); + } else { - } ); + // ...assume skeletal animation - var textures = this.parseTextures( json.textures, images ); - var materials = this.parseMaterials( json.materials, textures ); + var boneName = '.bones[' + bones[ h ].name + ']'; - var object = this.parseObject( json.object, geometries, materials ); + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.position', + animationKeys, 'pos', tracks ); - if ( json.animations ) { + addNonemptyTrack( + QuaternionKeyframeTrack, boneName + '.quaternion', + animationKeys, 'rot', tracks ); - object.animations = this.parseAnimations( json.animations ); + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.scale', + animationKeys, 'scl', tracks ); + + } } - if ( json.images === undefined || json.images.length === 0 ) { + if ( tracks.length === 0 ) { - if ( onLoad !== undefined ) onLoad( object ); + return null; } - return object; - - }, + var clip = new AnimationClip( clipName, duration, tracks ); - parseGeometries: function ( json ) { + return clip; - var geometries = {}; + } - if ( json !== undefined ) { + } ); - var geometryLoader = new JSONLoader(); - var bufferGeometryLoader = new BufferGeometryLoader(); + Object.assign( AnimationClip.prototype, { - for ( var i = 0, l = json.length; i < l; i ++ ) { + resetDuration: function () { - var geometry; - var data = json[ i ]; + var tracks = this.tracks, duration = 0; - switch ( data.type ) { + for ( var i = 0, n = tracks.length; i !== n; ++ i ) { - case 'PlaneGeometry': - case 'PlaneBufferGeometry': + var track = this.tracks[ i ]; - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - break; + } - case 'BoxGeometry': - case 'BoxBufferGeometry': - case 'CubeGeometry': // backwards compatible + this.duration = duration; - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); + }, - break; + trim: function () { - case 'CircleGeometry': - case 'CircleBufferGeometry': + for ( var i = 0; i < this.tracks.length; i ++ ) { - geometry = new Geometries[ data.type ]( - data.radius, - data.segments, - data.thetaStart, - data.thetaLength - ); + this.tracks[ i ].trim( 0, this.duration ); - break; + } - case 'CylinderGeometry': - case 'CylinderBufferGeometry': + return this; - geometry = new Geometries[ data.type ]( - data.radiusTop, - data.radiusBottom, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded, - data.thetaStart, - data.thetaLength - ); + }, - break; + optimize: function () { - case 'ConeGeometry': - case 'ConeBufferGeometry': + for ( var i = 0; i < this.tracks.length; i ++ ) { - geometry = new Geometries[ data.type ]( - data.radius, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded, - data.thetaStart, - data.thetaLength - ); + this.tracks[ i ].optimize(); - break; + } - case 'SphereGeometry': - case 'SphereBufferGeometry': + return this; - geometry = new Geometries[ data.type ]( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); + } - break; + } ); - case 'DodecahedronGeometry': - case 'DodecahedronBufferGeometry': - case 'IcosahedronGeometry': - case 'IcosahedronBufferGeometry': - case 'OctahedronGeometry': - case 'OctahedronBufferGeometry': - case 'TetrahedronGeometry': - case 'TetrahedronBufferGeometry': + /** + * @author mrdoob / http://mrdoob.com/ + */ - geometry = new Geometries[ data.type ]( - data.radius, - data.detail - ); + function MaterialLoader( manager ) { - break; + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.textures = {}; - case 'RingGeometry': - case 'RingBufferGeometry': + } - geometry = new Geometries[ data.type ]( - data.innerRadius, - data.outerRadius, - data.thetaSegments, - data.phiSegments, - data.thetaStart, - data.thetaLength - ); + Object.assign( MaterialLoader.prototype, { - break; + load: function ( url, onLoad, onProgress, onError ) { - case 'TorusGeometry': - case 'TorusBufferGeometry': + var scope = this; - geometry = new Geometries[ data.type ]( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { - break; + onLoad( scope.parse( JSON.parse( text ) ) ); - case 'TorusKnotGeometry': - case 'TorusKnotBufferGeometry': + }, onProgress, onError ); - geometry = new Geometries[ data.type ]( - data.radius, - data.tube, - data.tubularSegments, - data.radialSegments, - data.p, - data.q - ); + }, - break; + setTextures: function ( value ) { - case 'LatheGeometry': - case 'LatheBufferGeometry': + this.textures = value; - geometry = new Geometries[ data.type ]( - data.points, - data.segments, - data.phiStart, - data.phiLength - ); + }, - break; + parse: function ( json ) { - case 'PolyhedronGeometry': - case 'PolyhedronBufferGeometry': + var textures = this.textures; - geometry = new Geometries[ data.type ]( - data.vertices, - data.indices, - data.radius, - data.details - ); + function getTexture( name ) { - break; + if ( textures[ name ] === undefined ) { - case 'BufferGeometry': + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); - geometry = bufferGeometryLoader.parse( data ); + } - break; + return textures[ name ]; - case 'Geometry': + } - geometry = geometryLoader.parse( data, this.texturePath ).geometry; + var material = new Materials[ json.type ](); - break; + if ( json.uuid !== undefined ) material.uuid = json.uuid; + if ( json.name !== undefined ) material.name = json.name; + if ( json.color !== undefined ) material.color.setHex( json.color ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metalness !== undefined ) material.metalness = json.metalness; + if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; + if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; + if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; + if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; + if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; + if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; + if ( json.fog !== undefined ) material.fog = json.fog; + if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; + if ( json.blending !== undefined ) material.blending = json.blending; + if ( json.side !== undefined ) material.side = json.side; + if ( json.opacity !== undefined ) material.opacity = json.opacity; + if ( json.transparent !== undefined ) material.transparent = json.transparent; + if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; + if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; + if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; + if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; + if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; + if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; - default: + if ( json.rotation !== undefined ) material.rotation = json.rotation; - console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); + if ( json.linewidth !== 1 ) material.linewidth = json.linewidth; + if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; + if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; + if ( json.scale !== undefined ) material.scale = json.scale; - continue; + if ( json.skinning !== undefined ) material.skinning = json.skinning; + if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; + if ( json.dithering !== undefined ) material.dithering = json.dithering; - } + if ( json.visible !== undefined ) material.visible = json.visible; + if ( json.userData !== undefined ) material.userData = json.userData; - geometry.uuid = data.uuid; + // Deprecated - if ( data.name !== undefined ) geometry.name = data.name; + if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading - geometries[ data.uuid ] = geometry; + // for PointsMaterial - } + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - } + // maps - return geometries; + if ( json.map !== undefined ) material.map = getTexture( json.map ); - }, + if ( json.alphaMap !== undefined ) { - parseMaterials: function ( json, textures ) { + material.alphaMap = getTexture( json.alphaMap ); + material.transparent = true; - var materials = {}; + } - if ( json !== undefined ) { + if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); + if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; - var loader = new MaterialLoader(); - loader.setTextures( textures ); + if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); + if ( json.normalScale !== undefined ) { - for ( var i = 0, l = json.length; i < l; i ++ ) { + var normalScale = json.normalScale; - var data = json[ i ]; + if ( Array.isArray( normalScale ) === false ) { - if ( data.type === 'MultiMaterial' ) { + // Blender exporter used to export a scalar. See #7459 - // Deprecated + normalScale = [ normalScale, normalScale ]; - var array = []; + } - for ( var j = 0; j < data.materials.length; j ++ ) { + material.normalScale = new Vector2().fromArray( normalScale ); - array.push( loader.parse( data.materials[ j ] ) ); + } - } + if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); + if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; + if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; - materials[ data.uuid ] = array; + if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); + if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); - } else { + if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); + if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; - materials[ data.uuid ] = loader.parse( data ); + if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); - } + if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - } + if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - } + if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); + if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - return materials; + if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); + if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; - }, + if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - parseAnimations: function ( json ) { + return material; - var animations = []; + } - for ( var i = 0; i < json.length; i ++ ) { + } ); - var clip = AnimationClip.parse( json[ i ] ); + /** + * @author mrdoob / http://mrdoob.com/ + */ - animations.push( clip ); + function BufferGeometryLoader( manager ) { - } + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - return animations; + } - }, + Object.assign( BufferGeometryLoader.prototype, { - parseImages: function ( json, onLoad ) { + load: function ( url, onLoad, onProgress, onError ) { var scope = this; - var images = {}; - function loadImage( url ) { - - scope.manager.itemStart( url ); + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { - return loader.load( url, function () { + onLoad( scope.parse( JSON.parse( text ) ) ); - scope.manager.itemEnd( url ); + }, onProgress, onError ); - }, undefined, function () { + }, - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + parse: function ( json ) { - } ); + var geometry = new BufferGeometry(); - } + var index = json.data.index; - if ( json !== undefined && json.length > 0 ) { + if ( index !== undefined ) { - var manager = new LoadingManager( onLoad ); + var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); + geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - var loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); + } - for ( var i = 0, l = json.length; i < l; i ++ ) { + var attributes = json.data.attributes; - var image = json[ i ]; - var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; + for ( var key in attributes ) { - images[ image.uuid ] = loadImage( path ); + var attribute = attributes[ key ]; + var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); - } + geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); } - return images; - - }, + var groups = json.data.groups || json.data.drawcalls || json.data.offsets; - parseTextures: function ( json, images ) { + if ( groups !== undefined ) { - function parseConstant( value, type ) { + for ( var i = 0, n = groups.length; i !== n; ++ i ) { - if ( typeof value === 'number' ) return value; + var group = groups[ i ]; - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + geometry.addGroup( group.start, group.count, group.materialIndex ); - return type[ value ]; + } } - var textures = {}; - - if ( json !== undefined ) { + var boundingSphere = json.data.boundingSphere; - for ( var i = 0, l = json.length; i < l; i ++ ) { + if ( boundingSphere !== undefined ) { - var data = json[ i ]; + var center = new Vector3(); - if ( data.image === undefined ) { + if ( boundingSphere.center !== undefined ) { - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); + center.fromArray( boundingSphere.center ); - } + } - if ( images[ data.image ] === undefined ) { + geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + } - } + return geometry; - var texture = new Texture( images[ data.image ] ); - texture.needsUpdate = true; + } - texture.uuid = data.uuid; + } ); - if ( data.name !== undefined ) texture.name = data.name; + var TYPED_ARRAYS = { + Int8Array: Int8Array, + Uint8Array: Uint8Array, + // Workaround for IE11 pre KB2929437. See #11440 + Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, + Int16Array: Int16Array, + Uint16Array: Uint16Array, + Int32Array: Int32Array, + Uint32Array: Uint32Array, + Float32Array: Float32Array, + Float64Array: Float64Array + }; - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); + /** + * @author alteredq / http://alteredqualia.com/ + */ - if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); - if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); - if ( data.center !== undefined ) texture.center.fromArray( data.center ); - if ( data.rotation !== undefined ) texture.rotation = data.rotation; + function Loader() { - if ( data.wrap !== undefined ) { + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); + } - } + Loader.Handlers = { - if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); - if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); - if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + handlers: [], - if ( data.flipY !== undefined ) texture.flipY = data.flipY; + add: function ( regex, loader ) { - textures[ data.uuid ] = texture; + this.handlers.push( regex, loader ); - } + }, - } + get: function ( file ) { - return textures; + var handlers = this.handlers; - }, + for ( var i = 0, l = handlers.length; i < l; i += 2 ) { - parseObject: function () { + var regex = handlers[ i ]; + var loader = handlers[ i + 1 ]; - var matrix = new Matrix4(); + if ( regex.test( file ) ) { - return function parseObject( data, geometries, materials ) { + return loader; - var object; + } - function getGeometry( name ) { + } - if ( geometries[ name ] === undefined ) { + return null; - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + } - } + }; - return geometries[ name ]; + Object.assign( Loader.prototype, { - } + crossOrigin: undefined, - function getMaterial( name ) { + initMaterials: function ( materials, texturePath, crossOrigin ) { - if ( name === undefined ) return undefined; + var array = []; - if ( Array.isArray( name ) ) { + for ( var i = 0; i < materials.length; ++ i ) { - var array = []; + array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); - for ( var i = 0, l = name.length; i < l; i ++ ) { + } - var uuid = name[ i ]; + return array; - if ( materials[ uuid ] === undefined ) { + }, - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + createMaterial: ( function () { - } + var BlendingMode = { + NoBlending: NoBlending, + NormalBlending: NormalBlending, + AdditiveBlending: AdditiveBlending, + SubtractiveBlending: SubtractiveBlending, + MultiplyBlending: MultiplyBlending, + CustomBlending: CustomBlending + }; - array.push( materials[ uuid ] ); + var color = new Color(); + var textureLoader = new TextureLoader(); + var materialLoader = new MaterialLoader(); - } + return function createMaterial( m, texturePath, crossOrigin ) { - return array; + // convert from old material format - } + var textures = {}; - if ( materials[ name ] === undefined ) { + function loadTexture( path, repeat, offset, wrap, anisotropy ) { - console.warn( 'THREE.ObjectLoader: Undefined material', name ); + var fullPath = texturePath + path; + var loader = Loader.Handlers.get( fullPath ); - } + var texture; - return materials[ name ]; + if ( loader !== null ) { - } + texture = loader.load( fullPath ); - switch ( data.type ) { + } else { - case 'Scene': + textureLoader.setCrossOrigin( crossOrigin ); + texture = textureLoader.load( fullPath ); - object = new Scene(); + } - if ( data.background !== undefined ) { + if ( repeat !== undefined ) { - if ( Number.isInteger( data.background ) ) { + texture.repeat.fromArray( repeat ); - object.background = new Color( data.background ); + if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; - } + } - } + if ( offset !== undefined ) { - if ( data.fog !== undefined ) { + texture.offset.fromArray( offset ); - if ( data.fog.type === 'Fog' ) { + } - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); + if ( wrap !== undefined ) { - } else if ( data.fog.type === 'FogExp2' ) { + if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; + if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; - object.fog = new FogExp2( data.fog.color, data.fog.density ); + if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; + if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; - } + } - } + if ( anisotropy !== undefined ) { - break; + texture.anisotropy = anisotropy; - case 'PerspectiveCamera': + } - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + var uuid = _Math.generateUUID(); - if ( data.focus !== undefined ) object.focus = data.focus; - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; - if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + textures[ uuid ] = texture; - break; + return uuid; - case 'OrthographicCamera': + } - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + // - break; + var json = { + uuid: _Math.generateUUID(), + type: 'MeshLambertMaterial' + }; - case 'AmbientLight': + for ( var name in m ) { - object = new AmbientLight( data.color, data.intensity ); + var value = m[ name ]; - break; + switch ( name ) { - case 'DirectionalLight': + case 'DbgColor': + case 'DbgIndex': + case 'opticalDensity': + case 'illumination': + break; + case 'DbgName': + json.name = value; + break; + case 'blending': + json.blending = BlendingMode[ value ]; + break; + case 'colorAmbient': + case 'mapAmbient': + console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); + break; + case 'colorDiffuse': + json.color = color.fromArray( value ).getHex(); + break; + case 'colorSpecular': + json.specular = color.fromArray( value ).getHex(); + break; + case 'colorEmissive': + json.emissive = color.fromArray( value ).getHex(); + break; + case 'specularCoef': + json.shininess = value; + break; + case 'shading': + if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; + if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; + if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; + break; + case 'mapDiffuse': + json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); + break; + case 'mapDiffuseRepeat': + case 'mapDiffuseOffset': + case 'mapDiffuseWrap': + case 'mapDiffuseAnisotropy': + break; + case 'mapEmissive': + json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); + break; + case 'mapEmissiveRepeat': + case 'mapEmissiveOffset': + case 'mapEmissiveWrap': + case 'mapEmissiveAnisotropy': + break; + case 'mapLight': + json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); + break; + case 'mapLightRepeat': + case 'mapLightOffset': + case 'mapLightWrap': + case 'mapLightAnisotropy': + break; + case 'mapAO': + json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); + break; + case 'mapAORepeat': + case 'mapAOOffset': + case 'mapAOWrap': + case 'mapAOAnisotropy': + break; + case 'mapBump': + json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); + break; + case 'mapBumpScale': + json.bumpScale = value; + break; + case 'mapBumpRepeat': + case 'mapBumpOffset': + case 'mapBumpWrap': + case 'mapBumpAnisotropy': + break; + case 'mapNormal': + json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); + break; + case 'mapNormalFactor': + json.normalScale = [ value, value ]; + break; + case 'mapNormalRepeat': + case 'mapNormalOffset': + case 'mapNormalWrap': + case 'mapNormalAnisotropy': + break; + case 'mapSpecular': + json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); + break; + case 'mapSpecularRepeat': + case 'mapSpecularOffset': + case 'mapSpecularWrap': + case 'mapSpecularAnisotropy': + break; + case 'mapMetalness': + json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); + break; + case 'mapMetalnessRepeat': + case 'mapMetalnessOffset': + case 'mapMetalnessWrap': + case 'mapMetalnessAnisotropy': + break; + case 'mapRoughness': + json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); + break; + case 'mapRoughnessRepeat': + case 'mapRoughnessOffset': + case 'mapRoughnessWrap': + case 'mapRoughnessAnisotropy': + break; + case 'mapAlpha': + json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); + break; + case 'mapAlphaRepeat': + case 'mapAlphaOffset': + case 'mapAlphaWrap': + case 'mapAlphaAnisotropy': + break; + case 'flipSided': + json.side = BackSide; + break; + case 'doubleSided': + json.side = DoubleSide; + break; + case 'transparency': + console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); + json.opacity = value; + break; + case 'depthTest': + case 'depthWrite': + case 'colorWrite': + case 'opacity': + case 'reflectivity': + case 'transparent': + case 'visible': + case 'wireframe': + json[ name ] = value; + break; + case 'vertexColors': + if ( value === true ) json.vertexColors = VertexColors; + if ( value === 'face' ) json.vertexColors = FaceColors; + break; + default: + console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); + break; - object = new DirectionalLight( data.color, data.intensity ); + } - break; + } - case 'PointLight': + if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; + if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); + if ( json.opacity < 1 ) json.transparent = true; - break; + materialLoader.setTextures( textures ); - case 'RectAreaLight': + return materialLoader.parse( json ); - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); + }; - break; + } )() - case 'SpotLight': + } ); - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); + /** + * @author Don McCurdy / https://www.donmccurdy.com + */ - break; + var LoaderUtils = { - case 'HemisphereLight': + decodeText: function ( array ) { - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); + if ( typeof TextDecoder !== 'undefined' ) { - break; + return new TextDecoder().decode( array ); - case 'SkinnedMesh': + } - console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); + // Avoid the String.fromCharCode.apply(null, array) shortcut, which + // throws a "maximum call stack size exceeded" error for large arrays. - case 'Mesh': + var s = ''; - var geometry = getGeometry( data.geometry ); - var material = getMaterial( data.material ); + for ( var i = 0, il = array.length; i < il; i ++ ) { - if ( geometry.bones && geometry.bones.length > 0 ) { + // Implicitly assumes little-endian. + s += String.fromCharCode( array[ i ] ); - object = new SkinnedMesh( geometry, material ); + } - } else { + return s; - object = new Mesh( geometry, material ); + }, - } + extractUrlBase: function ( url ) { - break; + var parts = url.split( '/' ); - case 'LOD': + if ( parts.length === 1 ) return './'; - object = new LOD(); + parts.pop(); - break; + return parts.join( '/' ) + '/'; - case 'Line': + } - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); + }; - break; + /** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - case 'LineLoop': + function JSONLoader( manager ) { - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); + if ( typeof manager === 'boolean' ) { - break; + console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); + manager = undefined; - case 'LineSegments': + } - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - break; + this.withCredentials = false; - case 'PointCloud': - case 'Points': + } - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); + Object.assign( JSONLoader.prototype, { - break; + load: function ( url, onLoad, onProgress, onError ) { - case 'Sprite': + var scope = this; - object = new Sprite( getMaterial( data.material ) ); + var texturePath = this.texturePath && ( typeof this.texturePath === 'string' ) ? this.texturePath : LoaderUtils.extractUrlBase( url ); - break; + var loader = new FileLoader( this.manager ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { - case 'Group': + var json = JSON.parse( text ); + var metadata = json.metadata; - object = new Group(); + if ( metadata !== undefined ) { - break; + var type = metadata.type; - default: + if ( type !== undefined ) { - object = new Object3D(); + if ( type.toLowerCase() === 'object' ) { - } + console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); + return; - object.uuid = data.uuid; + } - if ( data.name !== undefined ) object.name = data.name; - if ( data.matrix !== undefined ) { + if ( type.toLowerCase() === 'scene' ) { - matrix.fromArray( data.matrix ); - matrix.decompose( object.position, object.quaternion, object.scale ); + console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); + return; - } else { + } - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + } } - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + var object = scope.parse( json, texturePath ); + onLoad( object.geometry, object.materials ); - if ( data.shadow ) { + }, onProgress, onError ); - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); + }, - } + setTexturePath: function ( value ) { - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.userData !== undefined ) object.userData = data.userData; + this.texturePath = value; - if ( data.children !== undefined ) { + }, - var children = data.children; + parse: ( function () { - for ( var i = 0; i < children.length; i ++ ) { + function parseModel( json, geometry ) { - object.add( this.parseObject( children[ i ], geometries, materials ) ); + function isBitSet( value, position ) { - } + return value & ( 1 << position ); } - if ( data.type === 'LOD' ) { + var i, j, fi, - var levels = data.levels; + offset, zLength, - for ( var l = 0; l < levels.length; l ++ ) { + colorIndex, normalIndex, uvIndex, materialIndex, - var level = levels[ l ]; - var child = object.getObjectByProperty( 'uuid', level.object ); + type, + isQuad, + hasMaterial, + hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, - if ( child !== undefined ) { + vertex, face, faceA, faceB, hex, normal, - object.addLevel( child, level.distance ); + uvLayer, uv, u, v, - } + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, - } + scale = json.scale, - } + nUvLayers = 0; - return object; - }; + if ( json.uvs !== undefined ) { - }() + // disregard empty arrays - } ); + for ( i = 0; i < json.uvs.length; i ++ ) { - var TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - SphericalReflectionMapping: SphericalReflectionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubeUVRefractionMapping: CubeUVRefractionMapping - }; + if ( json.uvs[ i ].length ) nUvLayers ++; - var TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping - }; + } - var TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipMapNearestFilter: NearestMipMapNearestFilter, - NearestMipMapLinearFilter: NearestMipMapLinearFilter, - LinearFilter: LinearFilter, - LinearMipMapNearestFilter: LinearMipMapNearestFilter, - LinearMipMapLinearFilter: LinearMipMapLinearFilter - }; + for ( i = 0; i < nUvLayers; i ++ ) { + + geometry.faceVertexUvs[ i ] = []; - /** - * @author thespite / http://clicktorelease.com/ - */ + } - function ImageBitmapLoader( manager ) { + } - if ( typeof createImageBitmap === 'undefined' ) { + offset = 0; + zLength = vertices.length; - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); + while ( offset < zLength ) { - } + vertex = new Vector3(); - if ( typeof fetch === 'undefined' ) { + vertex.x = vertices[ offset ++ ] * scale; + vertex.y = vertices[ offset ++ ] * scale; + vertex.z = vertices[ offset ++ ] * scale; - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); + geometry.vertices.push( vertex ); - } + } - this.manager = manager !== undefined ? manager : DefaultLoadingManager; - this.options = undefined; + offset = 0; + zLength = faces.length; - } + while ( offset < zLength ) { - ImageBitmapLoader.prototype = { + type = faces[ offset ++ ]; - constructor: ImageBitmapLoader, + isQuad = isBitSet( type, 0 ); + hasMaterial = isBitSet( type, 1 ); + hasFaceVertexUv = isBitSet( type, 3 ); + hasFaceNormal = isBitSet( type, 4 ); + hasFaceVertexNormal = isBitSet( type, 5 ); + hasFaceColor = isBitSet( type, 6 ); + hasFaceVertexColor = isBitSet( type, 7 ); - setOptions: function setOptions( options ) { + // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); - this.options = options; + if ( isQuad ) { - return this; + faceA = new Face3(); + faceA.a = faces[ offset ]; + faceA.b = faces[ offset + 1 ]; + faceA.c = faces[ offset + 3 ]; - }, + faceB = new Face3(); + faceB.a = faces[ offset + 1 ]; + faceB.b = faces[ offset + 2 ]; + faceB.c = faces[ offset + 3 ]; - load: function load( url, onLoad, onProgress, onError ) { + offset += 4; - if ( url === undefined ) url = ''; + if ( hasMaterial ) { - if ( this.path !== undefined ) url = this.path + url; + materialIndex = faces[ offset ++ ]; + faceA.materialIndex = materialIndex; + faceB.materialIndex = materialIndex; - var scope = this; + } - var cached = Cache.get( url ); + // to get face <=> uv index correspondence - if ( cached !== undefined ) { + fi = geometry.faces.length; - scope.manager.itemStart( url ); + if ( hasFaceVertexUv ) { - setTimeout( function () { + for ( i = 0; i < nUvLayers; i ++ ) { - if ( onLoad ) onLoad( cached ); + uvLayer = json.uvs[ i ]; - scope.manager.itemEnd( url ); + geometry.faceVertexUvs[ i ][ fi ] = []; + geometry.faceVertexUvs[ i ][ fi + 1 ] = []; - }, 0 ); + for ( j = 0; j < 4; j ++ ) { - return cached; + uvIndex = faces[ offset ++ ]; - } + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; - fetch( url ).then( function ( res ) { + uv = new Vector2( u, v ); - return res.blob(); + if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); + if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); - } ).then( function ( blob ) { + } - return createImageBitmap( blob, scope.options ); + } - } ).then( function ( imageBitmap ) { + } - Cache.add( url, imageBitmap ); + if ( hasFaceNormal ) { - if ( onLoad ) onLoad( imageBitmap ); + normalIndex = faces[ offset ++ ] * 3; - scope.manager.itemEnd( url ); + faceA.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - } ).catch( function ( e ) { + faceB.normal.copy( faceA.normal ); - if ( onError ) onError( e ); + } - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + if ( hasFaceVertexNormal ) { - } ); + for ( i = 0; i < 4; i ++ ) { - }, + normalIndex = faces[ offset ++ ] * 3; - setCrossOrigin: function ( /* value */ ) { + normal = new Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - return this; - }, + if ( i !== 2 ) faceA.vertexNormals.push( normal ); + if ( i !== 0 ) faceB.vertexNormals.push( normal ); - setPath: function ( value ) { + } - this.path = value; - return this; + } - } - }; + if ( hasFaceColor ) { - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Bezier Curves formulas obtained from - * http://en.wikipedia.org/wiki/Bézier_curve - */ + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; - function CatmullRom( t, p0, p1, p2, p3 ) { + faceA.color.setHex( hex ); + faceB.color.setHex( hex ); - var v0 = ( p2 - p0 ) * 0.5; - var v1 = ( p3 - p1 ) * 0.5; - var t2 = t * t; - var t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + } - } - // + if ( hasFaceVertexColor ) { - function QuadraticBezierP0( t, p ) { + for ( i = 0; i < 4; i ++ ) { - var k = 1 - t; - return k * k * p; + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; - } + if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); + if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); - function QuadraticBezierP1( t, p ) { + } - return 2 * ( 1 - t ) * t * p; + } - } + geometry.faces.push( faceA ); + geometry.faces.push( faceB ); - function QuadraticBezierP2( t, p ) { + } else { - return t * t * p; + face = new Face3(); + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; - } + if ( hasMaterial ) { - function QuadraticBezier( t, p0, p1, p2 ) { + materialIndex = faces[ offset ++ ]; + face.materialIndex = materialIndex; - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); + } - } + // to get face <=> uv index correspondence - // + fi = geometry.faces.length; - function CubicBezierP0( t, p ) { + if ( hasFaceVertexUv ) { - var k = 1 - t; - return k * k * k * p; + for ( i = 0; i < nUvLayers; i ++ ) { - } + uvLayer = json.uvs[ i ]; - function CubicBezierP1( t, p ) { + geometry.faceVertexUvs[ i ][ fi ] = []; - var k = 1 - t; - return 3 * k * k * t * p; + for ( j = 0; j < 3; j ++ ) { - } + uvIndex = faces[ offset ++ ]; - function CubicBezierP2( t, p ) { + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; - return 3 * ( 1 - t ) * t * t * p; + uv = new Vector2( u, v ); - } + geometry.faceVertexUvs[ i ][ fi ].push( uv ); - function CubicBezierP3( t, p ) { + } - return t * t * t * p; + } - } + } - function CubicBezier( t, p0, p1, p2, p3 ) { + if ( hasFaceNormal ) { - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); + normalIndex = faces[ offset ++ ] * 3; - } + face.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object - * - * Some common of curve methods: - * .getPoint( t, optionalTarget ), .getTangent( t ) - * .getPointAt( u, optionalTarget ), .getTangentAt( u ) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following curves inherit from THREE.Curve: - * - * -- 2D curves -- - * THREE.ArcCurve - * THREE.CubicBezierCurve - * THREE.EllipseCurve - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.SplineCurve - * - * -- 3D curves -- - * THREE.CatmullRomCurve3 - * THREE.CubicBezierCurve3 - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * - * A series of curves can be represented as a THREE.CurvePath. - * - **/ + } - /************************************************************** - * Abstract Curve base class - **************************************************************/ + if ( hasFaceVertexNormal ) { - function Curve() { + for ( i = 0; i < 3; i ++ ) { - this.type = 'Curve'; + normalIndex = faces[ offset ++ ] * 3; - this.arcLengthDivisions = 200; + normal = new Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - } + face.vertexNormals.push( normal ); - Object.assign( Curve.prototype, { + } - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] + } - getPoint: function ( /* t, optionalTarget */ ) { - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; + if ( hasFaceColor ) { - }, + colorIndex = faces[ offset ++ ]; + face.color.setHex( colors[ colorIndex ] ); - // Get point at relative position in curve according to arc length - // - u [0 .. 1] + } - getPointAt: function ( u, optionalTarget ) { - var t = this.getUtoTmapping( u ); - return this.getPoint( t, optionalTarget ); + if ( hasFaceVertexColor ) { - }, + for ( i = 0; i < 3; i ++ ) { - // Get sequence of points using getPoint( t ) + colorIndex = faces[ offset ++ ]; + face.vertexColors.push( new Color( colors[ colorIndex ] ) ); - getPoints: function ( divisions ) { + } - if ( divisions === undefined ) divisions = 5; + } - var points = []; + geometry.faces.push( face ); - for ( var d = 0; d <= divisions; d ++ ) { + } - points.push( this.getPoint( d / divisions ) ); + } } - return points; + function parseSkin( json, geometry ) { - }, + var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; - // Get sequence of points using getPointAt( u ) + if ( json.skinWeights ) { - getSpacedPoints: function ( divisions ) { + for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { - if ( divisions === undefined ) divisions = 5; + var x = json.skinWeights[ i ]; + var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; + var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; + var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; - var points = []; + geometry.skinWeights.push( new Vector4( x, y, z, w ) ); - for ( var d = 0; d <= divisions; d ++ ) { + } - points.push( this.getPointAt( d / divisions ) ); + } - } + if ( json.skinIndices ) { - return points; + for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { - }, + var a = json.skinIndices[ i ]; + var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; + var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; + var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; - // Get total curve arc length + geometry.skinIndices.push( new Vector4( a, b, c, d ) ); - getLength: function () { + } - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; + } - }, + geometry.bones = json.bones; - // Get list of cumulative segment lengths + if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { - getLengths: function ( divisions ) { + console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); - if ( divisions === undefined ) divisions = this.arcLengthDivisions; + } - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { + } - return this.cacheArcLengths; + function parseMorphing( json, geometry ) { - } + var scale = json.scale; - this.needsUpdate = false; + if ( json.morphTargets !== undefined ) { - var cache = []; - var current, last = this.getPoint( 0 ); - var p, sum = 0; + for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { - cache.push( 0 ); + geometry.morphTargets[ i ] = {}; + geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; + geometry.morphTargets[ i ].vertices = []; - for ( p = 1; p <= divisions; p ++ ) { + var dstVertices = geometry.morphTargets[ i ].vertices; + var srcVertices = json.morphTargets[ i ].vertices; - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; + for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { - } + var vertex = new Vector3(); + vertex.x = srcVertices[ v ] * scale; + vertex.y = srcVertices[ v + 1 ] * scale; + vertex.z = srcVertices[ v + 2 ] * scale; - this.cacheArcLengths = cache; + dstVertices.push( vertex ); - return cache; // { sums: cache, sum: sum }; Sum is in the last element. + } - }, + } - updateArcLengths: function () { + } - this.needsUpdate = true; - this.getLengths(); + if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { - }, + console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant + var faces = geometry.faces; + var morphColors = json.morphColors[ 0 ].colors; - getUtoTmapping: function ( u, distance ) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - var arcLengths = this.getLengths(); + faces[ i ].color.fromArray( morphColors, i * 3 ); - var i = 0, il = arcLengths.length; + } - var targetArcLength; // The targeted u distance value to get + } - if ( distance ) { + } - targetArcLength = distance; + function parseAnimations( json, geometry ) { - } else { + var outputAnimations = []; - targetArcLength = u * arcLengths[ il - 1 ]; + // parse old style Bone/Hierarchy animations + var animations = []; - } + if ( json.animation !== undefined ) { - // binary search for the index with largest value smaller than target u distance + animations.push( json.animation ); - var low = 0, high = il - 1, comparison; + } - while ( low <= high ) { + if ( json.animations !== undefined ) { - i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats + if ( json.animations.length ) { - comparison = arcLengths[ i ] - targetArcLength; + animations = animations.concat( json.animations ); - if ( comparison < 0 ) { + } else { - low = i + 1; + animations.push( json.animations ); - } else if ( comparison > 0 ) { + } - high = i - 1; + } - } else { + for ( var i = 0; i < animations.length; i ++ ) { - high = i; - break; + var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); + if ( clip ) outputAnimations.push( clip ); - // DONE + } + + // parse implicit morph animations + if ( geometry.morphTargets ) { + + // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. + var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); + outputAnimations = outputAnimations.concat( morphAnimationClips ); } + if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; + } - i = high; + return function ( json, texturePath ) { - if ( arcLengths[ i ] === targetArcLength ) { + if ( json.data !== undefined ) { - return i / ( il - 1 ); + // Geometry 4.0 spec + json = json.data; - } + } - // we could get finer grain at lengths, or use simple interpolation between two points + if ( json.scale !== undefined ) { - var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; + json.scale = 1.0 / json.scale; - var segmentLength = lengthAfter - lengthBefore; + } else { - // determine where we are between the 'before' and 'after' points + json.scale = 1.0; - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + } - // add that fractional amount to t + var geometry = new Geometry(); - var t = ( i + segmentFraction ) / ( il - 1 ); + parseModel( json, geometry ); + parseSkin( json, geometry ); + parseMorphing( json, geometry ); + parseAnimations( json, geometry ); - return t; + geometry.computeFaceNormals(); + geometry.computeBoundingSphere(); - }, + if ( json.materials === undefined || json.materials.length === 0 ) { - // Returns a unit vector tangent at t - // In case any sub curve does not implement its tangent derivation, - // 2 points a small delta apart will be used to find its gradient - // which seems to give a reasonable approximation + return { geometry: geometry }; - getTangent: function ( t ) { + } else { - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; + var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); - // Capping in case of danger + return { geometry: geometry, materials: materials }; - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; + } - var pt1 = this.getPoint( t1 ); - var pt2 = this.getPoint( t2 ); + }; + + } )() + + } ); + + /** + * @author mrdoob / http://mrdoob.com/ + */ + + function ObjectLoader( manager ) { - var vec = pt2.clone().sub( pt1 ); - return vec.normalize(); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.texturePath = ''; - }, + } - getTangentAt: function ( u ) { + Object.assign( ObjectLoader.prototype, { - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); + load: function ( url, onLoad, onProgress, onError ) { - }, + if ( this.texturePath === '' ) { - computeFrenetFrames: function ( segments, closed ) { + this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + } - var normal = new Vector3(); + var scope = this; - var tangents = []; - var normals = []; - var binormals = []; + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { - var vec = new Vector3(); - var mat = new Matrix4(); + var json = null; - var i, u, theta; + try { - // compute the tangent vectors for each segment on the curve + json = JSON.parse( text ); - for ( i = 0; i <= segments; i ++ ) { + } catch ( error ) { - u = i / segments; + if ( onError !== undefined ) onError( error ); - tangents[ i ] = this.getTangentAt( u ); - tangents[ i ].normalize(); + console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - } + return; - // select an initial normal vector perpendicular to the first tangent vector, - // and in the direction of the minimum tangent xyz component + } - normals[ 0 ] = new Vector3(); - binormals[ 0 ] = new Vector3(); - var min = Number.MAX_VALUE; - var tx = Math.abs( tangents[ 0 ].x ); - var ty = Math.abs( tangents[ 0 ].y ); - var tz = Math.abs( tangents[ 0 ].z ); + var metadata = json.metadata; - if ( tx <= min ) { + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - min = tx; - normal.set( 1, 0, 0 ); + console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); + return; - } + } - if ( ty <= min ) { + scope.parse( json, onLoad ); - min = ty; - normal.set( 0, 1, 0 ); + }, onProgress, onError ); - } + }, - if ( tz <= min ) { + setTexturePath: function ( value ) { - normal.set( 0, 0, 1 ); + this.texturePath = value; - } + }, - vec.crossVectors( tangents[ 0 ], normal ).normalize(); + setCrossOrigin: function ( value ) { - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + this.crossOrigin = value; + }, - // compute the slowly-varying normal and binormal vectors for each segment on the curve + parse: function ( json, onLoad ) { - for ( i = 1; i <= segments; i ++ ) { + var shapes = this.parseShape( json.shapes ); + var geometries = this.parseGeometries( json.geometries, shapes ); - normals[ i ] = normals[ i - 1 ].clone(); + var images = this.parseImages( json.images, function () { - binormals[ i ] = binormals[ i - 1 ].clone(); + if ( onLoad !== undefined ) onLoad( object ); - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); + } ); - if ( vec.length() > Number.EPSILON ) { + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); - vec.normalize(); + var object = this.parseObject( json.object, geometries, materials ); - theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors + if ( json.animations ) { - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + object.animations = this.parseAnimations( json.animations ); - } + } - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + if ( json.images === undefined || json.images.length === 0 ) { + + if ( onLoad !== undefined ) onLoad( object ); } - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + return object; - if ( closed === true ) { + }, - theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; + parseShape: function ( json ) { - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { + var shapes = {}; - theta = - theta; + if ( json !== undefined ) { - } + for ( var i = 0, l = json.length; i < l; i ++ ) { - for ( i = 1; i <= segments; i ++ ) { + var shape = new Shape().fromJSON( json[ i ] ); - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + shapes[ shape.uuid ] = shape; } } - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; + return shapes; }, - clone: function () { - - return new this.constructor().copy( this ); + parseGeometries: function ( json, shapes ) { - }, + var geometries = {}; - copy: function ( source ) { + if ( json !== undefined ) { - this.arcLengthDivisions = source.arcLengthDivisions; + var geometryLoader = new JSONLoader(); + var bufferGeometryLoader = new BufferGeometryLoader(); - return this; + for ( var i = 0, l = json.length; i < l; i ++ ) { - } + var geometry; + var data = json[ i ]; - } ); + switch ( data.type ) { - function LineCurve( v1, v2 ) { + case 'PlaneGeometry': + case 'PlaneBufferGeometry': - Curve.call( this ); + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); - this.type = 'LineCurve'; + break; - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); + case 'BoxGeometry': + case 'BoxBufferGeometry': + case 'CubeGeometry': // backwards compatible - } + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); - LineCurve.prototype = Object.create( Curve.prototype ); - LineCurve.prototype.constructor = LineCurve; + break; - LineCurve.prototype.isLineCurve = true; + case 'CircleGeometry': + case 'CircleBufferGeometry': - LineCurve.prototype.getPoint = function ( t, optionalTarget ) { + geometry = new Geometries[ data.type ]( + data.radius, + data.segments, + data.thetaStart, + data.thetaLength + ); - var point = optionalTarget || new Vector2(); + break; - if ( t === 1 ) { + case 'CylinderGeometry': + case 'CylinderBufferGeometry': - point.copy( this.v2 ); + geometry = new Geometries[ data.type ]( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); - } else { + break; - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); + case 'ConeGeometry': + case 'ConeBufferGeometry': - } + geometry = new Geometries[ data.type ]( + data.radius, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); - return point; + break; - }; + case 'SphereGeometry': + case 'SphereBufferGeometry': - // Line curve is linear, so we can overwrite default getPointAt + geometry = new Geometries[ data.type ]( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); - LineCurve.prototype.getPointAt = function ( u, optionalTarget ) { + break; - return this.getPoint( u, optionalTarget ); + case 'DodecahedronGeometry': + case 'DodecahedronBufferGeometry': + case 'IcosahedronGeometry': + case 'IcosahedronBufferGeometry': + case 'OctahedronGeometry': + case 'OctahedronBufferGeometry': + case 'TetrahedronGeometry': + case 'TetrahedronBufferGeometry': - }; + geometry = new Geometries[ data.type ]( + data.radius, + data.detail + ); - LineCurve.prototype.getTangent = function ( /* t */ ) { + break; - var tangent = this.v2.clone().sub( this.v1 ); + case 'RingGeometry': + case 'RingBufferGeometry': - return tangent.normalize(); + geometry = new Geometries[ data.type ]( + data.innerRadius, + data.outerRadius, + data.thetaSegments, + data.phiSegments, + data.thetaStart, + data.thetaLength + ); - }; + break; - LineCurve.prototype.copy = function ( source ) { + case 'TorusGeometry': + case 'TorusBufferGeometry': - Curve.prototype.copy.call( this, source ); + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + break; - return this; + case 'TorusKnotGeometry': + case 'TorusKnotBufferGeometry': - }; + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.tubularSegments, + data.radialSegments, + data.p, + data.q + ); - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - **/ + break; - /************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ + case 'LatheGeometry': + case 'LatheBufferGeometry': - function CurvePath() { + geometry = new Geometries[ data.type ]( + data.points, + data.segments, + data.phiStart, + data.phiLength + ); - Curve.call( this ); + break; - this.type = 'CurvePath'; + case 'PolyhedronGeometry': + case 'PolyhedronBufferGeometry': - this.curves = []; - this.autoClose = false; // Automatically closes the path + geometry = new Geometries[ data.type ]( + data.vertices, + data.indices, + data.radius, + data.details + ); - } + break; - CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { + case 'ShapeGeometry': + case 'ShapeBufferGeometry': - constructor: CurvePath, + var geometryShapes = []; - add: function ( curve ) { + for ( var i = 0, l = data.shapes.length; i < l; i ++ ) { - this.curves.push( curve ); + var shape = shapes[ data.shapes[ i ] ]; - }, + geometryShapes.push( shape ); - closePath: function () { + } - // 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 ); + geometry = new Geometries[ data.type ]( + geometryShapes, + data.curveSegments + ); - if ( ! startPoint.equals( endPoint ) ) { + break; - this.curves.push( new LineCurve( endPoint, startPoint ) ); + case 'BufferGeometry': - } + geometry = bufferGeometryLoader.parse( data ); - }, + break; - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: + case 'Geometry': - // 1. Length of each sub path have to be known - // 2. Locate and identify type of curve - // 3. Get t for the curve - // 4. Return curve.getPointAt(t') + geometry = geometryLoader.parse( data, this.texturePath ).geometry; - getPoint: function ( t ) { + break; - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0; + default: - // To think about boundaries points. + console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); - while ( i < curveLengths.length ) { + continue; - if ( curveLengths[ i ] >= d ) { + } - var diff = curveLengths[ i ] - d; - var curve = this.curves[ i ]; + geometry.uuid = data.uuid; - var segmentLength = curve.getLength(); - var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + if ( data.name !== undefined ) geometry.name = data.name; - return curve.getPointAt( u ); + geometries[ data.uuid ] = geometry; } - i ++; - } - return null; - - // loop where sum != 0, sum > d , sum+1 0 ) { - if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates + var manager = new LoadingManager( onLoad ); - points.push( point ); - last = point; + var loader = new ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); - } + 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; - if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { + images[ image.uuid ] = loadImage( path ); - points.push( points[ 0 ] ); + } } - return points; + return images; }, - copy: function ( source ) { - - Curve.prototype.copy.call( this, source ); + parseTextures: function ( json, images ) { - this.curves = []; + function parseConstant( value, type ) { - for ( var i = 0, l = source.curves.length; i < l; i ++ ) { + if ( typeof value === 'number' ) return value; - var curve = source.curves[ i ]; + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); - this.curves.push( curve.clone() ); + return type[ value ]; } - this.autoClose = source.autoClose; + var textures = {}; - return this; + if ( json !== undefined ) { - } + for ( var i = 0, l = json.length; i < l; i ++ ) { - } ); + var data = json[ i ]; - function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + if ( data.image === undefined ) { - Curve.call( this ); + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - this.type = 'EllipseCurve'; + } - this.aX = aX || 0; - this.aY = aY || 0; + if ( images[ data.image ] === undefined ) { - this.xRadius = xRadius || 1; - this.yRadius = yRadius || 1; + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + + } - this.aStartAngle = aStartAngle || 0; - this.aEndAngle = aEndAngle || 2 * Math.PI; + var texture = new Texture( images[ data.image ] ); + texture.needsUpdate = true; - this.aClockwise = aClockwise || false; + texture.uuid = data.uuid; - this.aRotation = aRotation || 0; + if ( data.name !== undefined ) texture.name = data.name; - } + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); - EllipseCurve.prototype = Object.create( Curve.prototype ); - EllipseCurve.prototype.constructor = EllipseCurve; + if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); + if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); + if ( data.center !== undefined ) texture.center.fromArray( data.center ); + if ( data.rotation !== undefined ) texture.rotation = data.rotation; - EllipseCurve.prototype.isEllipseCurve = true; + if ( data.wrap !== undefined ) { - EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) { + texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - var point = optionalTarget || new Vector2(); + } - var twoPi = Math.PI * 2; - var deltaAngle = this.aEndAngle - this.aStartAngle; - var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); + if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; + if ( data.flipY !== undefined ) texture.flipY = data.flipY; - if ( deltaAngle < Number.EPSILON ) { + textures[ data.uuid ] = texture; - if ( samePoints ) { + } - deltaAngle = 0; + } - } else { + return textures; - deltaAngle = twoPi; + }, - } + parseObject: function () { - } + var matrix = new Matrix4(); - if ( this.aClockwise === true && ! samePoints ) { + return function parseObject( data, geometries, materials ) { - if ( deltaAngle === twoPi ) { + var object; - deltaAngle = - twoPi; + function getGeometry( name ) { - } else { + if ( geometries[ name ] === undefined ) { - deltaAngle = deltaAngle - twoPi; + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - } + } - } + return geometries[ name ]; - var angle = this.aStartAngle + t * deltaAngle; - var x = this.aX + this.xRadius * Math.cos( angle ); - var y = this.aY + this.yRadius * Math.sin( angle ); + } - if ( this.aRotation !== 0 ) { + function getMaterial( name ) { - var cos = Math.cos( this.aRotation ); - var sin = Math.sin( this.aRotation ); + if ( name === undefined ) return undefined; - var tx = x - this.aX; - var ty = y - this.aY; + if ( Array.isArray( name ) ) { - // Rotate the point about the center of the ellipse. - x = tx * cos - ty * sin + this.aX; - y = tx * sin + ty * cos + this.aY; + var array = []; - } + for ( var i = 0, l = name.length; i < l; i ++ ) { - return point.set( x, y ); + var uuid = name[ i ]; - }; + if ( materials[ uuid ] === undefined ) { - EllipseCurve.prototype.copy = function ( source ) { + console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); - Curve.prototype.copy.call( this, source ); + } - this.aX = source.aX; - this.aY = source.aY; + array.push( materials[ uuid ] ); - this.xRadius = source.xRadius; - this.yRadius = source.yRadius; + } - this.aStartAngle = source.aStartAngle; - this.aEndAngle = source.aEndAngle; + return array; - this.aClockwise = source.aClockwise; + } - this.aRotation = source.aRotation; + if ( materials[ name ] === undefined ) { - return this; + console.warn( 'THREE.ObjectLoader: Undefined material', name ); - }; + } - function SplineCurve( points /* array of Vector2 */ ) { + return materials[ name ]; - Curve.call( this ); + } - this.type = 'SplineCurve'; + switch ( data.type ) { - this.points = points || []; + case 'Scene': - } + object = new Scene(); - SplineCurve.prototype = Object.create( Curve.prototype ); - SplineCurve.prototype.constructor = SplineCurve; + if ( data.background !== undefined ) { - SplineCurve.prototype.isSplineCurve = true; + if ( Number.isInteger( data.background ) ) { - SplineCurve.prototype.getPoint = function ( t, optionalTarget ) { + object.background = new Color( data.background ); - var point = optionalTarget || new Vector2(); + } - var points = this.points; - var p = ( points.length - 1 ) * t; + } - var intPoint = Math.floor( p ); - var weight = p - intPoint; + if ( data.fog !== undefined ) { - var p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; - var p1 = points[ intPoint ]; - var p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; - var p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; + if ( data.fog.type === 'Fog' ) { - point.set( - CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), - CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) - ); + object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - return point; + } else if ( data.fog.type === 'FogExp2' ) { - }; + object.fog = new FogExp2( data.fog.color, data.fog.density ); - SplineCurve.prototype.copy = function ( source ) { + } - Curve.prototype.copy.call( this, source ); + } - this.points = []; + break; - for ( var i = 0, l = source.points.length; i < l; i ++ ) { + case 'PerspectiveCamera': - var point = source.points[ i ]; + object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - this.points.push( point.clone() ); + if ( data.focus !== undefined ) object.focus = data.focus; + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; + if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - } + break; - return this; + case 'OrthographicCamera': - }; + object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - function CubicBezierCurve( v0, v1, v2, v3 ) { + break; - Curve.call( this ); + case 'AmbientLight': - this.type = 'CubicBezierCurve'; + object = new AmbientLight( data.color, data.intensity ); - this.v0 = v0 || new Vector2(); - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); - this.v3 = v3 || new Vector2(); + break; - } + case 'DirectionalLight': - CubicBezierCurve.prototype = Object.create( Curve.prototype ); - CubicBezierCurve.prototype.constructor = CubicBezierCurve; + object = new DirectionalLight( data.color, data.intensity ); - CubicBezierCurve.prototype.isCubicBezierCurve = true; + break; - CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { + case 'PointLight': - var point = optionalTarget || new Vector2(); + object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + break; - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) - ); + case 'RectAreaLight': - return point; + object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); - }; + break; - CubicBezierCurve.prototype.copy = function ( source ) { + case 'SpotLight': - Curve.prototype.copy.call( this, source ); + object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); + break; - return this; + case 'HemisphereLight': - }; + object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - function QuadraticBezierCurve( v0, v1, v2 ) { + break; - Curve.call( this ); + case 'SkinnedMesh': - this.type = 'QuadraticBezierCurve'; + console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); - this.v0 = v0 || new Vector2(); - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); + case 'Mesh': - } + var geometry = getGeometry( data.geometry ); + var material = getMaterial( data.material ); - QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); - QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; + if ( geometry.bones && geometry.bones.length > 0 ) { - QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; + object = new SkinnedMesh( geometry, material ); - QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { + } else { - var point = optionalTarget || new Vector2(); + object = new Mesh( geometry, material ); - var v0 = this.v0, v1 = this.v1, v2 = this.v2; + } - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ) - ); + break; - return point; + case 'LOD': - }; + object = new LOD(); - QuadraticBezierCurve.prototype.copy = function ( source ) { + break; - Curve.prototype.copy.call( this, source ); + case 'Line': - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - return this; + break; - }; + case 'LineLoop': - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. - **/ + object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - function Path( points ) { + break; - CurvePath.call( this ); + case 'LineSegments': - this.type = 'Path'; + object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - this.currentPoint = new Vector2(); + break; - if ( points ) { + case 'PointCloud': + case 'Points': - this.setFromPoints( points ); + object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - } + break; - } + case 'Sprite': - Path.prototype = Object.assign( Object.create( CurvePath.prototype ), { + object = new Sprite( getMaterial( data.material ) ); - constructor: Path, + break; - setFromPoints: function ( points ) { + case 'Group': - this.moveTo( points[ 0 ].x, points[ 0 ].y ); + object = new Group(); - for ( var i = 1, l = points.length; i < l; i ++ ) { + break; - this.lineTo( points[ i ].x, points[ i ].y ); + default: - } + object = new Object3D(); - }, + } - moveTo: function ( x, y ) { + object.uuid = data.uuid; - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? + if ( data.name !== undefined ) object.name = data.name; + if ( data.matrix !== undefined ) { - }, + matrix.fromArray( data.matrix ); + matrix.decompose( object.position, object.quaternion, object.scale ); - lineTo: function ( x, y ) { + } else { - var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - this.currentPoint.set( x, y ); + } - }, + if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; + if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; - quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + if ( data.shadow ) { - var curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); + if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; + if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; + if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); + if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); - this.curves.push( curve ); + } - this.currentPoint.set( aX, aY ); + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.userData !== undefined ) object.userData = data.userData; - }, + if ( data.children !== undefined ) { - bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + var children = data.children; - var curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); + for ( var i = 0; i < children.length; i ++ ) { - this.curves.push( curve ); + object.add( this.parseObject( children[ i ], geometries, materials ) ); - this.currentPoint.set( aX, aY ); + } - }, + } - splineThru: function ( pts /*Array of Vector*/ ) { + if ( data.type === 'LOD' ) { - var npts = [ this.currentPoint.clone() ].concat( pts ); + var levels = data.levels; - var curve = new SplineCurve( npts ); - this.curves.push( curve ); + for ( var l = 0; l < levels.length; l ++ ) { - this.currentPoint.copy( pts[ pts.length - 1 ] ); + var level = levels[ l ]; + var child = object.getObjectByProperty( 'uuid', level.object ); - }, + if ( child !== undefined ) { - arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + object.addLevel( child, level.distance ); - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; + } - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); + } - }, + } - absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + return object; - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + }; - }, + }() - ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + } ); - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; + var TEXTURE_MAPPING = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + SphericalReflectionMapping: SphericalReflectionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping, + CubeUVRefractionMapping: CubeUVRefractionMapping + }; - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + var TEXTURE_WRAPPING = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping + }; - }, + var TEXTURE_FILTER = { + NearestFilter: NearestFilter, + NearestMipMapNearestFilter: NearestMipMapNearestFilter, + NearestMipMapLinearFilter: NearestMipMapLinearFilter, + LinearFilter: LinearFilter, + LinearMipMapNearestFilter: LinearMipMapNearestFilter, + LinearMipMapLinearFilter: LinearMipMapLinearFilter + }; - absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + /** + * @author thespite / http://clicktorelease.com/ + */ - var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + function ImageBitmapLoader( manager ) { - if ( this.curves.length > 0 ) { + if ( typeof createImageBitmap === 'undefined' ) { - // if a previous curve is present, attempt to join - var firstPoint = curve.getPoint( 0 ); + console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - if ( ! firstPoint.equals( this.currentPoint ) ) { + } - this.lineTo( firstPoint.x, firstPoint.y ); + if ( typeof fetch === 'undefined' ) { - } + console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - } + } - this.curves.push( curve ); + this.manager = manager !== undefined ? manager : DefaultLoadingManager; + this.options = undefined; - var lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); + } - }, + ImageBitmapLoader.prototype = { - copy: function ( source ) { + constructor: ImageBitmapLoader, - CurvePath.prototype.copy.call( this, source ); + setOptions: function setOptions( options ) { - this.currentPoint.copy( source.currentPoint ); + this.options = options; return this; - } + }, - } ); + load: function load( url, onLoad, onProgress, onError ) { - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Defines a 2d shape plane using paths. - **/ + if ( url === undefined ) url = ''; - // STEP 1 Create a path. - // STEP 2 Turn path into shape. - // STEP 3 ExtrudeGeometry takes in Shape/Shapes - // STEP 3a - Extract points from each shape, turn to vertices - // STEP 3b - Triangulate each shape, add faces. + if ( this.path !== undefined ) url = this.path + url; - function Shape( points ) { + var scope = this; - Path.call( this, points ); + var cached = Cache.get( url ); - this.type = 'Shape'; + if ( cached !== undefined ) { - this.holes = []; + scope.manager.itemStart( url ); - } + setTimeout( function () { - Shape.prototype = Object.assign( Object.create( Path.prototype ), { + if ( onLoad ) onLoad( cached ); - constructor: Shape, + scope.manager.itemEnd( url ); - getPointsHoles: function ( divisions ) { + }, 0 ); - var holesPts = []; + return cached; - for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + } - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); + fetch( url ).then( function ( res ) { - } + return res.blob(); - return holesPts; + } ).then( function ( blob ) { - }, + return createImageBitmap( blob, scope.options ); - // get points of shape and holes (keypoints based on segments parameter) + } ).then( function ( imageBitmap ) { - extractPoints: function ( divisions ) { + Cache.add( url, imageBitmap ); - return { + if ( onLoad ) onLoad( imageBitmap ); - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) + scope.manager.itemEnd( url ); - }; + } ).catch( function ( e ) { - }, + if ( onError ) onError( e ); - copy: function ( source ) { + scope.manager.itemEnd( url ); + scope.manager.itemError( url ); - Path.prototype.copy.call( this, source ); + } ); - this.holes = []; + }, - for ( var i = 0, l = source.holes.length; i < l; i ++ ) { + setCrossOrigin: function ( /* value */ ) { - var hole = source.holes[ i ]; + return this; - this.holes.push( hole.clone() ); + }, - } + setPath: function ( value ) { + this.path = value; return this; } - } ); + }; /** * @author zz85 / http://www.lab4games.net/zz85/blog @@ -43022,375 +43902,6 @@ AxesHelper.prototype = Object.create( LineSegments.prototype ); AxesHelper.prototype.constructor = AxesHelper; - /** - * @author zz85 https://github.com/zz85 - * - * Centripetal CatmullRom Curve - which is useful for avoiding - * cusps and self-intersections in non-uniform catmull rom curves. - * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf - * - * curve.type accepts centripetal(default), chordal and catmullrom - * curve.tension is used for catmullrom which defaults to 0.5 - */ - - - /* - Based on an optimized c++ solution in - - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ - - http://ideone.com/NoEbVM - - This CubicPoly class could be used for reusing some variables and calculations, - but for three.js curve use, it could be possible inlined and flatten into a single function call - which can be placed in CurveUtils. - */ - - function CubicPoly() { - - var c0 = 0, c1 = 0, c2 = 0, c3 = 0; - - /* - * Compute coefficients for a cubic polynomial - * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 - * such that - * p(0) = x0, p(1) = x1 - * and - * p'(0) = t0, p'(1) = t1. - */ - function init( x0, x1, t0, t1 ) { - - c0 = x0; - c1 = t0; - c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; - c3 = 2 * x0 - 2 * x1 + t0 + t1; - - } - - return { - - initCatmullRom: function ( x0, x1, x2, x3, tension ) { - - init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - - }, - - initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - - // compute tangents when parameterized in [t1,t2] - var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; - var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - - // rescale tangents for parametrization in [0,1] - t1 *= dt1; - t2 *= dt1; - - init( x1, x2, t1, t2 ); - - }, - - calc: function ( t ) { - - var t2 = t * t; - var t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; - - } - - }; - - } - - // - - var tmp = new Vector3(); - var px = new CubicPoly(); - var py = new CubicPoly(); - var pz = new CubicPoly(); - - function CatmullRomCurve3( points, closed, curveType, tension ) { - - Curve.call( this ); - - this.type = 'CatmullRomCurve3'; - - this.points = points || []; - this.closed = closed || false; - this.curveType = curveType || 'centripetal'; - this.tension = tension || 0.5; - - } - - CatmullRomCurve3.prototype = Object.create( Curve.prototype ); - CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; - - CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; - - CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) { - - var point = optionalTarget || new Vector3(); - - var points = this.points; - var l = points.length; - - var p = ( l - ( this.closed ? 0 : 1 ) ) * t; - var intPoint = Math.floor( p ); - var weight = p - intPoint; - - if ( this.closed ) { - - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - - } else if ( weight === 0 && intPoint === l - 1 ) { - - intPoint = l - 2; - weight = 1; - - } - - var p0, p1, p2, p3; // 4 points - - if ( this.closed || intPoint > 0 ) { - - p0 = points[ ( intPoint - 1 ) % l ]; - - } else { - - // extrapolate first point - tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); - p0 = tmp; - - } - - p1 = points[ intPoint % l ]; - p2 = points[ ( intPoint + 1 ) % l ]; - - if ( this.closed || intPoint + 2 < l ) { - - p3 = points[ ( intPoint + 2 ) % l ]; - - } else { - - // extrapolate last point - tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); - p3 = tmp; - - } - - if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - - // init Centripetal / Chordal Catmull-Rom - var pow = this.curveType === 'chordal' ? 0.5 : 0.25; - var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); - var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); - var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - - // safety check for repeated points - if ( dt1 < 1e-4 ) dt1 = 1.0; - if ( dt0 < 1e-4 ) dt0 = dt1; - if ( dt2 < 1e-4 ) dt2 = dt1; - - px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); - py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); - pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - - } else if ( this.curveType === 'catmullrom' ) { - - px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); - py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); - pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); - - } - - point.set( - px.calc( weight ), - py.calc( weight ), - pz.calc( weight ) - ); - - return point; - - }; - - CatmullRomCurve3.prototype.copy = function ( source ) { - - Curve.prototype.copy.call( this, source ); - - this.points = []; - - for ( var i = 0, l = source.points.length; i < l; i ++ ) { - - var point = source.points[ i ]; - - this.points.push( point.clone() ); - - } - - this.closed = source.closed; - this.curveType = source.curveType; - this.tension = source.tension; - - return this; - - }; - - function CubicBezierCurve3( v0, v1, v2, v3 ) { - - Curve.call( this ); - - this.type = 'CubicBezierCurve3'; - - this.v0 = v0 || new Vector3(); - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); - this.v3 = v3 || new Vector3(); - - } - - CubicBezierCurve3.prototype = Object.create( Curve.prototype ); - CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; - - CubicBezierCurve3.prototype.isCubicBezierCurve3 = true; - - CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - - var point = optionalTarget || new Vector3(); - - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), - CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) - ); - - return point; - - }; - - CubicBezierCurve3.prototype.copy = function ( source ) { - - Curve.prototype.copy.call( this, source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); - - return this; - - }; - - function QuadraticBezierCurve3( v0, v1, v2 ) { - - Curve.call( this ); - - this.type = 'QuadraticBezierCurve3'; - - this.v0 = v0 || new Vector3(); - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); - - } - - QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); - QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; - - QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; - - QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - - var point = optionalTarget || new Vector3(); - - var v0 = this.v0, v1 = this.v1, v2 = this.v2; - - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ), - QuadraticBezier( t, v0.z, v1.z, v2.z ) - ); - - return point; - - }; - - QuadraticBezierCurve3.prototype.copy = function ( source ) { - - Curve.prototype.copy.call( this, source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - }; - - function LineCurve3( v1, v2 ) { - - Curve.call( this ); - - this.type = 'LineCurve3'; - - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); - - } - - LineCurve3.prototype = Object.create( Curve.prototype ); - LineCurve3.prototype.constructor = LineCurve3; - - LineCurve3.prototype.isLineCurve3 = true; - - LineCurve3.prototype.getPoint = function ( t, optionalTarget ) { - - var point = optionalTarget || new Vector3(); - - if ( t === 1 ) { - - point.copy( this.v2 ); - - } else { - - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); - - } - - return point; - - }; - - // Line curve is linear, so we can overwrite default getPointAt - - LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) { - - return this.getPoint( u, optionalTarget ); - - }; - - LineCurve3.prototype.copy = function ( source ) { - - Curve.prototype.copy.call( this, source ); - - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - }; - - function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - this.type = 'ArcCurve'; - - } - - ArcCurve.prototype = Object.create( EllipseCurve.prototype ); - ArcCurve.prototype.constructor = ArcCurve; - - ArcCurve.prototype.isArcCurve = true; - /** * @author alteredq / http://alteredqualia.com/ */ @@ -45217,16 +45728,6 @@ exports.PlaneHelper = PlaneHelper; exports.ArrowHelper = ArrowHelper; exports.AxesHelper = AxesHelper; - exports.CatmullRomCurve3 = CatmullRomCurve3; - exports.CubicBezierCurve3 = CubicBezierCurve3; - exports.QuadraticBezierCurve3 = QuadraticBezierCurve3; - exports.LineCurve3 = LineCurve3; - exports.ArcCurve = ArcCurve; - exports.EllipseCurve = EllipseCurve; - exports.SplineCurve = SplineCurve; - exports.CubicBezierCurve = CubicBezierCurve; - exports.QuadraticBezierCurve = QuadraticBezierCurve; - exports.LineCurve = LineCurve; exports.Shape = Shape; exports.Path = Path; exports.ShapePath = ShapePath; @@ -45305,6 +45806,16 @@ exports.Uint8BufferAttribute = Uint8BufferAttribute; exports.Int8BufferAttribute = Int8BufferAttribute; exports.BufferAttribute = BufferAttribute; + exports.ArcCurve = ArcCurve; + exports.CatmullRomCurve3 = CatmullRomCurve3; + exports.CubicBezierCurve = CubicBezierCurve; + exports.CubicBezierCurve3 = CubicBezierCurve3; + exports.EllipseCurve = EllipseCurve; + exports.LineCurve = LineCurve; + exports.LineCurve3 = LineCurve3; + exports.QuadraticBezierCurve = QuadraticBezierCurve; + exports.QuadraticBezierCurve3 = QuadraticBezierCurve3; + exports.SplineCurve = SplineCurve; exports.REVISION = REVISION; exports.MOUSE = MOUSE; exports.CullFaceNone = CullFaceNone; diff --git a/build/three.min.js b/build/three.min.js index 8023471ae7..3ea1321b1d 100644 --- a/build/three.min.js +++ b/build/three.min.js @@ -1,110 +1,110 @@ // threejs.org/license -(function(l,xa){"object"===typeof exports&&"undefined"!==typeof module?xa(exports):"function"===typeof define&&define.amd?define(["exports"],xa):xa(l.THREE={})})(this,function(l){function xa(){}function D(a,b){this.x=a||0;this.y=b||0}function H(){this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];0=d||0=d||0 0 ) {\n\t\tfloat fogFactor = 0.0;\n\t\tif ( fogType == 1 ) {\n\t\t\tfogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t\t} else {\n\t\t\tconst float LOG2 = 1.442695;\n\t\t\tfogFactor = exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 );\n\t\t\tfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n\t\t}\n\t\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n\t}\n}"].join("\n")); -b.compileShader(M);b.compileShader(B);b.attachShader(x,M);b.attachShader(x,B);b.linkProgram(x);na=x;A=b.getAttribLocation(na,"position");J=b.getAttribLocation(na,"uv");f=b.getUniformLocation(na,"uvOffset");g=b.getUniformLocation(na,"uvScale");h=b.getUniformLocation(na,"rotation");k=b.getUniformLocation(na,"scale");m=b.getUniformLocation(na,"color");q=b.getUniformLocation(na,"map");n=b.getUniformLocation(na,"opacity");u=b.getUniformLocation(na,"modelViewMatrix");r=b.getUniformLocation(na,"projectionMatrix"); -t=b.getUniformLocation(na,"fogType");l=b.getUniformLocation(na,"fogDensity");w=b.getUniformLocation(na,"fogNear");z=b.getUniformLocation(na,"fogFar");y=b.getUniformLocation(na,"fogColor");b.getUniformLocation(na,"fogDepth");I=b.getUniformLocation(na,"alphaTest");x=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");x.width=8;x.height=8;M=x.getContext("2d");M.fillStyle="white";M.fillRect(0,0,8,8);Te=new sc(x)}c.useProgram(na);c.initAttributes();c.enableAttribute(A);c.enableAttribute(J); -c.disableUnusedAttributes();c.disable(b.CULL_FACE);c.enable(b.BLEND);b.bindBuffer(b.ARRAY_BUFFER,Ba);b.vertexAttribPointer(A,2,b.FLOAT,!1,16,0);b.vertexAttribPointer(J,2,b.FLOAT,!1,16,8);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,ma);b.uniformMatrix4fv(r,!1,D.projectionMatrix.elements);c.activeTexture(b.TEXTURE0);b.uniform1i(q,0);M=x=0;(B=p.fog)?(b.uniform3f(y,B.color.r,B.color.g,B.color.b),B.isFog?(b.uniform1f(w,B.near),b.uniform1f(z,B.far),b.uniform1i(t,1),M=x=1):B.isFogExp2&&(b.uniform1f(l,B.density), -b.uniform1i(t,2),M=x=2)):(b.uniform1i(t,0),M=x=0);for(var C=0,va=v.length;Cb&&(b=a[c]);return b}function C(){Object.defineProperty(this,"id",{value:dg+=2});this.uuid=O.generateUUID();this.name="";this.type="BufferGeometry";this.index=null;this.attributes={};this.morphAttributes= -{};this.groups=[];this.boundingSphere=this.boundingBox=null;this.drawRange={start:0,count:Infinity}}function Kb(a,b,c,d,e,f){L.call(this);this.type="BoxGeometry";this.parameters={width:a,height:b,depth:c,widthSegments:d,heightSegments:e,depthSegments:f};this.fromBufferGeometry(new mb(a,b,c,d,e,f));this.mergeVertices()}function mb(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,l,Ha,Ba,ma){var t=f/Ha,v=g/Ba,I=f/2,A=g/2,w=l/2;g=Ha+1;var z=Ba+1,y=f=0,J,x,B=new p;for(x=0;xm;m++){if(n=d[m])if(h=n[0],n=n[1]){q&&e.addAttribute("morphTarget"+m,q[h]);f&&e.addAttribute("morphNormal"+m,f[h]);c[m]=n;continue}c[m]=0}g.getUniforms().setValue(a,"morphTargetInfluences",c)}}}function lg(a,b,c){var d,e,f;this.setMode=function(a){d= +(a.bufferSubData(d,g.offset*h.BYTES_PER_ELEMENT,h.subarray(g.offset,g.offset+g.count)),g.count=-1),e.version=c.version)}}}function gb(a,b,c,d){this._x=a||0;this._y=b||0;this._z=c||0;this._order=d||gb.DefaultOrder}function Wd(){this.mask=1}function x(){Object.defineProperty(this,"id",{value:cg++});this.uuid=Q.generateUUID();this.name="";this.type="Object3D";this.parent=null;this.children=[];this.up=x.DefaultUp.clone();var a=new p,b=new gb,c=new ha,d=new p(1,1,1);b.onChange(function(){c.setFromEuler(b, +!1)});c.onChange(function(){b.setFromQuaternion(c,void 0,!1)});Object.defineProperties(this,{position:{enumerable:!0,value:a},rotation:{enumerable:!0,value:b},quaternion:{enumerable:!0,value:c},scale:{enumerable:!0,value:d},modelViewMatrix:{value:new O},normalMatrix:{value:new ma}});this.matrix=new O;this.matrixWorld=new O;this.matrixAutoUpdate=x.DefaultMatrixAutoUpdate;this.matrixWorldNeedsUpdate=!1;this.layers=new Wd;this.visible=!0;this.receiveShadow=this.castShadow=!1;this.frustumCulled=!0;this.renderOrder= +0;this.userData={}}function Ta(){x.call(this);this.type="Camera";this.matrixWorldInverse=new O;this.projectionMatrix=new O}function Lb(a,b,c,d,e,f){Ta.call(this);this.type="OrthographicCamera";this.zoom=1;this.view=null;this.left=a;this.right=b;this.top=c;this.bottom=d;this.near=void 0!==e?e:.1;this.far=void 0!==f?f:2E3;this.updateProjectionMatrix()}function Ya(a,b,c,d,e,f){this.a=a;this.b=b;this.c=c;this.normal=d&&d.isVector3?d:new p;this.vertexNormals=Array.isArray(d)?d:[];this.color=e&&e.isColor? +e:new H;this.vertexColors=Array.isArray(e)?e:[];this.materialIndex=void 0!==f?f:0}function L(){Object.defineProperty(this,"id",{value:dg+=2});this.uuid=Q.generateUUID();this.name="";this.type="Geometry";this.vertices=[];this.colors=[];this.faces=[];this.faceVertexUvs=[[]];this.morphTargets=[];this.morphNormals=[];this.skinWeights=[];this.skinIndices=[];this.lineDistances=[];this.boundingSphere=this.boundingBox=null;this.groupsNeedUpdate=this.lineDistancesNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate= +this.uvsNeedUpdate=this.verticesNeedUpdate=this.elementsNeedUpdate=!1}function M(a,b,c){if(Array.isArray(a))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.uuid=Q.generateUUID();this.name="";this.array=a;this.itemSize=b;this.count=void 0!==a?a.length/b:0;this.normalized=!0===c;this.dynamic=!1;this.updateRange={offset:0,count:-1};this.onUploadCallback=function(){};this.version=0}function uc(a,b,c){M.call(this,new Int8Array(a),b,c)}function vc(a,b,c){M.call(this,new Uint8Array(a), +b,c)}function wc(a,b,c){M.call(this,new Uint8ClampedArray(a),b,c)}function xc(a,b,c){M.call(this,new Int16Array(a),b,c)}function ob(a,b,c){M.call(this,new Uint16Array(a),b,c)}function yc(a,b,c){M.call(this,new Int32Array(a),b,c)}function pb(a,b,c){M.call(this,new Uint32Array(a),b,c)}function B(a,b,c){M.call(this,new Float32Array(a),b,c)}function zc(a,b,c){M.call(this,new Float64Array(a),b,c)}function Ve(){this.indices=[];this.vertices=[];this.normals=[];this.colors=[];this.uvs=[];this.uvs2=[];this.groups= +[];this.morphTargets={};this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.groupsNeedUpdate=this.uvsNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.verticesNeedUpdate=!1}function Xd(a){if(0===a.length)return-Infinity;for(var b=a[0],c=1,d=a.length;cb&&(b=a[c]);return b}function E(){Object.defineProperty(this,"id",{value:eg+=2});this.uuid=Q.generateUUID();this.name="";this.type="BufferGeometry";this.index=null;this.attributes={};this.morphAttributes= +{};this.groups=[];this.boundingSphere=this.boundingBox=null;this.drawRange={start:0,count:Infinity}}function Mb(a,b,c,d,e,f){L.call(this);this.type="BoxGeometry";this.parameters={width:a,height:b,depth:c,widthSegments:d,heightSegments:e,depthSegments:f};this.fromBufferGeometry(new qb(a,b,c,d,e,f));this.mergeVertices()}function qb(a,b,c,d,e,f){function g(a,b,c,d,e,f,g,l,Ha,Da,na){var t=f/Ha,v=g/Da,I=f/2,A=g/2,w=l/2;g=Ha+1;var z=Da+1,y=f=0,J,x,B=new p;for(x=0;xm;m++){if(n=d[m])if(h=n[0],n=n[1]){q&&e.addAttribute("morphTarget"+m,q[h]);f&&e.addAttribute("morphNormal"+m,f[h]);c[m]=n;continue}c[m]=0}g.getUniforms().setValue(a,"morphTargetInfluences",c)}}}function mg(a,b,c){var d,e,f;this.setMode=function(a){d= a};this.setIndex=function(a){e=a.type;f=a.bytesPerElement};this.render=function(b,h){a.drawElements(d,h,e,b*f);c.calls++;c.vertices+=h;d===a.TRIANGLES?c.faces+=h/3:d===a.POINTS&&(c.points+=h)};this.renderInstances=function(g,h,k){var m=b.get("ANGLE_instanced_arrays");null===m?console.error("THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays."):(m.drawElementsInstancedANGLE(d,k,e,h*f,g.maxInstancedCount),c.calls++,c.vertices+= -k*g.maxInstancedCount,d===a.TRIANGLES?c.faces+=g.maxInstancedCount*k/3:d===a.POINTS&&(c.points+=g.maxInstancedCount*k))}}function mg(a,b,c){var d;this.setMode=function(a){d=a};this.render=function(b,f){a.drawArrays(d,b,f);c.calls++;c.vertices+=f;d===a.TRIANGLES?c.faces+=f/3:d===a.POINTS&&(c.points+=f)};this.renderInstances=function(e,f,g){var h=b.get("ANGLE_instanced_arrays");if(null===h)console.error("THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays."); -else{var k=e.attributes.position;k.isInterleavedBufferAttribute?(g=k.data.count,h.drawArraysInstancedANGLE(d,0,g,e.maxInstancedCount)):h.drawArraysInstancedANGLE(d,f,g,e.maxInstancedCount);c.calls++;c.vertices+=g*e.maxInstancedCount;d===a.TRIANGLES?c.faces+=e.maxInstancedCount*g/3:d===a.POINTS&&(c.points+=e.maxInstancedCount*g)}}}function ng(a,b,c){function d(a){a=a.target;var g=e[a.id];null!==g.index&&b.remove(g.index);for(var k in g.attributes)b.remove(g.attributes[k]);a.removeEventListener("dispose", -d);delete e[a.id];if(k=f[a.id])b.remove(k),delete f[a.id];if(k=f[g.id])b.remove(k),delete f[g.id];c.geometries--}var e={},f={};return{get:function(a,b){var f=e[b.id];if(f)return f;b.addEventListener("dispose",d);b.isBufferGeometry?f=b:b.isGeometry&&(void 0===b._bufferGeometry&&(b._bufferGeometry=(new C).setFromObject(a)),f=b._bufferGeometry);e[b.id]=f;c.geometries++;return f},update:function(c){var d=c.index,e=c.attributes;null!==d&&b.update(d,a.ELEMENT_ARRAY_BUFFER);for(var f in e)b.update(e[f], -a.ARRAY_BUFFER);c=c.morphAttributes;for(f in c)for(var d=c[f],e=0,g=d.length;e/gm,function(a,c){a=Q[c];if(void 0===a)throw Error("Can not resolve #include <"+c+">");return Zd(a)})}function Ze(a){return a.replace(/for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g, -function(a,c,d,e){a="";for(c=parseInt(c);c/gm,function(a,c){a=R[c];if(void 0===a)throw Error("Can not resolve #include <"+c+">");return Zd(a)})}function Ze(a){return a.replace(/for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g, +function(a,c,d,e){a="";for(c=parseInt(c);cb||a.height>b){b/=Math.max(a.width,a.height);var c=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");c.width=Math.floor(a.width*b);c.height=Math.floor(a.height*b);c.getContext("2d").drawImage(a, -0,0,a.width,a.height,0,0,c.width,c.height);console.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+c.width+"x"+c.height,a);return c}return a}function k(a){return O.isPowerOfTwo(a.width)&&O.isPowerOfTwo(a.height)}function m(a,b){return a.generateMipmaps&&b&&1003!==a.minFilter&&1006!==a.minFilter}function q(b){return 1003===b||1004===b||1005===b?a.NEAREST:a.LINEAR}function n(b){b=b.target;b.removeEventListener("dispose",n);a:{var c=d.get(b);if(b.image&&c.__image__webglTextureCube)a.deleteTexture(c.__image__webglTextureCube); +m;k++){var q=e[k];if(q.code===g){h=q;++h.usedTimes;break}}void 0===h&&(h=new xg(a,b,g,c,d,f),e.push(h));return h};this.releaseProgram=function(a){if(0===--a.usedTimes){var b=e.indexOf(a);e[b]=e[e.length-1];e.pop();a.destroy()}};this.programs=e}function Ag(a,b,c,d,e,f,g){function h(a,b){if(a.width>b||a.height>b){b/=Math.max(a.width,a.height);var c=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");c.width=Math.floor(a.width*b);c.height=Math.floor(a.height*b);c.getContext("2d").drawImage(a, +0,0,a.width,a.height,0,0,c.width,c.height);console.warn("THREE.WebGLRenderer: image is too big ("+a.width+"x"+a.height+"). Resized to "+c.width+"x"+c.height,a);return c}return a}function k(a){return Q.isPowerOfTwo(a.width)&&Q.isPowerOfTwo(a.height)}function m(a,b){return a.generateMipmaps&&b&&1003!==a.minFilter&&1006!==a.minFilter}function q(b){return 1003===b||1004===b||1005===b?a.NEAREST:a.LINEAR}function n(b){b=b.target;b.removeEventListener("dispose",n);a:{var c=d.get(b);if(b.image&&c.__image__webglTextureCube)a.deleteTexture(c.__image__webglTextureCube); else{if(void 0===c.__webglInit)break a;a.deleteTexture(c.__webglTexture)}d.remove(b)}b.isVideoTexture&&delete y[b.id];g.textures--}function u(b){b=b.target;b.removeEventListener("dispose",u);var c=d.get(b),e=d.get(b.texture);if(b){void 0!==e.__webglTexture&&a.deleteTexture(e.__webglTexture);b.depthTexture&&b.depthTexture.dispose();if(b.isWebGLRenderTargetCube)for(e=0;6>e;e++)a.deleteFramebuffer(c.__webglFramebuffer[e]),c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer[e]);else a.deleteFramebuffer(c.__webglFramebuffer), c.__webglDepthbuffer&&a.deleteRenderbuffer(c.__webglDepthbuffer);d.remove(b.texture);d.remove(b)}g.textures--}function r(b,q){var u=d.get(b);if(0v;v++)l[v]=q||r?r?b.image[v].image:b.image[v]:h(b.image[v],e.maxCubemapSize); var p=k(l[0]),w=f.convert(b.format),A=f.convert(b.type);t(a.TEXTURE_CUBE_MAP,b,p);for(v=0;6>v;v++)if(q)for(var y,I=l[v].mipmaps,z=0,x=I.length;zn;n++)e.__webglFramebuffer[n]=a.createFramebuffer()}else e.__webglFramebuffer=a.createFramebuffer();if(h){c.bindTexture(a.TEXTURE_CUBE_MAP,f.__webglTexture);t(a.TEXTURE_CUBE_MAP,b.texture,q);for(n=0;6>n;n++)l(e.__webglFramebuffer[n],b,a.COLOR_ATTACHMENT0,a.TEXTURE_CUBE_MAP_POSITIVE_X+n); -m(b.texture,q)&&a.generateMipmap(a.TEXTURE_CUBE_MAP);c.bindTexture(a.TEXTURE_CUBE_MAP,null)}else c.bindTexture(a.TEXTURE_2D,f.__webglTexture),t(a.TEXTURE_2D,b.texture,q),l(e.__webglFramebuffer,b,a.COLOR_ATTACHMENT0,a.TEXTURE_2D),m(b.texture,q)&&a.generateMipmap(a.TEXTURE_2D),c.bindTexture(a.TEXTURE_2D,null);if(b.depthBuffer){e=d.get(b);f=!0===b.isWebGLRenderTargetCube;if(b.depthTexture){if(f)throw Error("target.depthTexture not supported in Cube render targets");if(b&&b.isWebGLRenderTargetCube)throw Error("Depth Texture with cube render targets is not supported"); +function(b){var e=d.get(b),f=d.get(b.texture);b.addEventListener("dispose",u);f.__webglTexture=a.createTexture();g.textures++;var h=!0===b.isWebGLRenderTargetCube,n=k(b);if(h){e.__webglFramebuffer=[];for(var q=0;6>q;q++)e.__webglFramebuffer[q]=a.createFramebuffer()}else e.__webglFramebuffer=a.createFramebuffer();if(h){c.bindTexture(a.TEXTURE_CUBE_MAP,f.__webglTexture);t(a.TEXTURE_CUBE_MAP,b.texture,n);for(q=0;6>q;q++)l(e.__webglFramebuffer[q],b,a.COLOR_ATTACHMENT0,a.TEXTURE_CUBE_MAP_POSITIVE_X+q); +m(b.texture,n)&&a.generateMipmap(a.TEXTURE_CUBE_MAP);c.bindTexture(a.TEXTURE_CUBE_MAP,null)}else c.bindTexture(a.TEXTURE_2D,f.__webglTexture),t(a.TEXTURE_2D,b.texture,n),l(e.__webglFramebuffer,b,a.COLOR_ATTACHMENT0,a.TEXTURE_2D),m(b.texture,n)&&a.generateMipmap(a.TEXTURE_2D),c.bindTexture(a.TEXTURE_2D,null);if(b.depthBuffer){e=d.get(b);f=!0===b.isWebGLRenderTargetCube;if(b.depthTexture){if(f)throw Error("target.depthTexture not supported in Cube render targets");if(b&&b.isWebGLRenderTargetCube)throw Error("Depth Texture with cube render targets is not supported"); a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer);if(!b.depthTexture||!b.depthTexture.isDepthTexture)throw Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");d.get(b.depthTexture).__webglTexture&&b.depthTexture.image.width===b.width&&b.depthTexture.image.height===b.height||(b.depthTexture.image.width=b.width,b.depthTexture.image.height=b.height,b.depthTexture.needsUpdate=!0);r(b.depthTexture,0);e=d.get(b.depthTexture).__webglTexture;if(1026===b.depthTexture.format)a.framebufferTexture2D(a.FRAMEBUFFER, a.DEPTH_ATTACHMENT,a.TEXTURE_2D,e,0);else if(1027===b.depthTexture.format)a.framebufferTexture2D(a.FRAMEBUFFER,a.DEPTH_STENCIL_ATTACHMENT,a.TEXTURE_2D,e,0);else throw Error("Unknown depthTexture format");}else if(f)for(e.__webglDepthbuffer=[],f=0;6>f;f++)a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer[f]),e.__webglDepthbuffer[f]=a.createRenderbuffer(),p(e.__webglDepthbuffer[f],b);else a.bindFramebuffer(a.FRAMEBUFFER,e.__webglFramebuffer),e.__webglDepthbuffer=a.createRenderbuffer(),p(e.__webglDepthbuffer, -b);a.bindFramebuffer(a.FRAMEBUFFER,null)}};this.updateRenderTargetMipmap=function(b){var e=b.texture,f=k(b);m(e,f)&&(b=b.isWebGLRenderTargetCube?a.TEXTURE_CUBE_MAP:a.TEXTURE_2D,e=d.get(e).__webglTexture,c.bindTexture(b,e),a.generateMipmap(b),c.bindTexture(b,null))};this.updateVideoTextures=function(){for(var a in y)y[a].update()}}function Ag(){var a={};return{get:function(b){b=b.uuid;var c=a[b];void 0===c&&(c={},a[b]=c);return c},remove:function(b){delete a[b.uuid]},clear:function(){a={}}}}function Bg(a, -b,c){function d(b,c,d){var e=new Uint8Array(4),f=a.createTexture();a.bindTexture(b,f);a.texParameteri(b,a.TEXTURE_MIN_FILTER,a.NEAREST);a.texParameteri(b,a.TEXTURE_MAG_FILTER,a.NEAREST);for(b=0;ba.matrixWorld.determinant();Z.setMaterial(e,h);h=u(c,b.fog,e,a);Q=""; -g(a,h,e)}else S.renderBufferDirect(c,b.fog,d,e,a,f);a.onAfterRender(S,b,c,d,e,f)}function n(a,b,c){var d=da.get(a);c=oa.getParameters(a,ua.state,C,b,Ia.numPlanes,Ia.numIntersection,c);var g=oa.getProgramCode(a,c),h=d.program,k=!0;if(void 0===h)a.addEventListener("dispose",e);else if(h.code!==g)f(a);else{if(void 0!==c.shaderID)return;k=!1}k&&(c.shaderID?(h=pb[c.shaderID],d.shader={name:a.type,uniforms:Ga.clone(h.uniforms),vertexShader:h.vertexShader,fragmentShader:h.fragmentShader}):d.shader={name:a.type, -uniforms:a.uniforms,vertexShader:a.vertexShader,fragmentShader:a.fragmentShader},a.onBeforeCompile(d.shader),h=oa.acquireProgram(a,d.shader,c,g),d.program=h,a.program=h);c=h.getAttributes();if(a.morphTargets)for(g=a.numSupportedMorphTargets=0;ga.matrixWorld.determinant();Z.setMaterial(e,h);h=u(c,b.fog,e,a);R=""; +g(a,h,e)}else S.renderBufferDirect(c,b.fog,d,e,a,f);a.onAfterRender(S,b,c,d,e,f)}function n(a,b,c){var d=ca.get(a);c=ma.getParameters(a,ua.state,C,b,Ja.numPlanes,Ja.numIntersection,c);var g=ma.getProgramCode(a,c),h=d.program,k=!0;if(void 0===h)a.addEventListener("dispose",e);else if(h.code!==g)f(a);else{if(void 0!==c.shaderID)return;k=!1}k&&(c.shaderID?(h=tb[c.shaderID],d.shader={name:a.type,uniforms:Ga.clone(h.uniforms),vertexShader:h.vertexShader,fragmentShader:h.fragmentShader}):d.shader={name:a.type, +uniforms:a.uniforms,vertexShader:a.vertexShader,fragmentShader:a.fragmentShader},a.onBeforeCompile(d.shader),h=ma.acquireProgram(a,d.shader,c,g),d.program=h,a.program=h);c=h.getAttributes();if(a.morphTargets)for(g=a.numSupportedMorphTargets=0;ge.matrixWorld.determinant();Z.setMaterial(d,g);var h=u(a,b,d,e);a=c.id+"_"+h.id+"_"+(!0===d.wireframe);var k=!1;a!==Q&&(Q=a,k=!0);e.morphTargetInfluences&&(xa.update(e,c,d,h),k=!0);var g=c.index,m=c.attributes.position;b=1;!0===d.wireframe&&(g=ra.getWireframeAttribute(c), +1E-4);b.emissiveMap&&(a.emissiveMap.value=b.emissiveMap);b.bumpMap&&(a.bumpMap.value=b.bumpMap,a.bumpScale.value=b.bumpScale);b.normalMap&&(a.normalMap.value=b.normalMap,a.normalScale.value.copy(b.normalScale));b.displacementMap&&(a.displacementMap.value=b.displacementMap,a.displacementScale.value=b.displacementScale,a.displacementBias.value=b.displacementBias)}console.log("THREE.WebGLRenderer","89");a=a||{};var v=void 0!==a.canvas?a.canvas:document.createElementNS("http://www.w3.org/1999/xhtml", +"canvas"),w=void 0!==a.context?a.context:null,z=void 0!==a.alpha?a.alpha:!1,y=void 0!==a.depth?a.depth:!0,I=void 0!==a.stencil?a.stencil:!0,A=void 0!==a.antialias?a.antialias:!1,J=void 0!==a.premultipliedAlpha?a.premultipliedAlpha:!0,x=void 0!==a.preserveDrawingBuffer?a.preserveDrawingBuffer:!1,B=void 0!==a.powerPreference?a.powerPreference:"default",D=[],C=[],E=null,H=[],la=[];this.domElement=v;this.context=null;this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear= +!0;this.clippingPlanes=[];this.localClippingEnabled=!1;this.gammaFactor=2;this.physicallyCorrectLights=this.gammaOutput=this.gammaInput=!1;this.toneMappingWhitePoint=this.toneMappingExposure=this.toneMapping=1;this.maxMorphTargets=8;this.maxMorphNormals=4;var S=this,L=!1,N=null,M=null,P=-1,R="",V=null,W=null,nb=new aa,X=new aa,G=null,Y=0,ea=v.width,U=v.height,wa=1,da=new aa(0,0,ea,U),fa=new aa(0,0,ea,U),$e=!1,$d=new rd,Ja=new Fg,sd=!1,ae=!1,td=new O,Ob=new p,ha={geometries:0,textures:0},ba={frame:0, +calls:0,vertices:0,faces:0,points:0};this.info={render:ba,memory:ha,programs:null};try{z={alpha:z,depth:y,stencil:I,antialias:A,premultipliedAlpha:J,preserveDrawingBuffer:x,powerPreference:B};v.addEventListener("webglcontextlost",c,!1);v.addEventListener("webglcontextrestored",d,!1);var F=w||v.getContext("webgl",z)||v.getContext("experimental-webgl",z);if(null===F){if(null!==v.getContext("webgl"))throw Error("Error creating WebGL context with your selected attributes.");throw Error("Error creating WebGL context."); +}void 0===F.getShaderPrecisionFormat&&(F.getShaderPrecisionFormat=function(){return{rangeMin:1,rangeMax:1,precision:1}})}catch(Gg){console.error("THREE.WebGLRenderer: "+Gg.message)}var ia,T,Z,ca,ga,qa,ra,ta,ua,ma,sa,ja,xa,ya,za,Aa,Ba,pa;b();var ka=new be(S);this.vr=ka;var Ea=new Ue(S,ta,T.maxTextureSize);this.shadowMap=Ea;this.getContext=function(){return F};this.getContextAttributes=function(){return F.getContextAttributes()};this.forceContextLoss=function(){var a=ia.get("WEBGL_lose_context");a&& +a.loseContext()};this.forceContextRestore=function(){var a=ia.get("WEBGL_lose_context");a&&a.restoreContext()};this.getPixelRatio=function(){return wa};this.setPixelRatio=function(a){void 0!==a&&(wa=a,this.setSize(ea,U,!1))};this.getSize=function(){return{width:ea,height:U}};this.setSize=function(a,b,c){var d=ka.getDevice();d&&d.isPresenting?console.warn("THREE.WebGLRenderer: Can't change size while VR device is presenting."):(ea=a,U=b,v.width=a*wa,v.height=b*wa,!1!==c&&(v.style.width=a+"px",v.style.height= +b+"px"),this.setViewport(0,0,a,b))};this.getDrawingBufferSize=function(){return{width:ea*wa,height:U*wa}};this.setDrawingBufferSize=function(a,b,c){ea=a;U=b;wa=c;v.width=a*c;v.height=b*c;this.setViewport(0,0,a,b)};this.setViewport=function(a,b,c,d){da.set(a,U-b-d,c,d);Z.viewport(nb.copy(da).multiplyScalar(wa))};this.setScissor=function(a,b,c,d){fa.set(a,U-b-d,c,d);Z.scissor(X.copy(fa).multiplyScalar(wa))};this.setScissorTest=function(a){Z.setScissorTest($e=a)};this.getClearColor=function(){return ja.getClearColor()}; +this.setClearColor=function(){ja.setClearColor.apply(ja,arguments)};this.getClearAlpha=function(){return ja.getClearAlpha()};this.setClearAlpha=function(){ja.setClearAlpha.apply(ja,arguments)};this.clear=function(a,b,c){var d=0;if(void 0===a||a)d|=F.COLOR_BUFFER_BIT;if(void 0===b||b)d|=F.DEPTH_BUFFER_BIT;if(void 0===c||c)d|=F.STENCIL_BUFFER_BIT;F.clear(d)};this.clearColor=function(){this.clear(!0,!1,!1)};this.clearDepth=function(){this.clear(!1,!0,!1)};this.clearStencil=function(){this.clear(!1,!1, +!0)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.dispose=function(){v.removeEventListener("webglcontextlost",c,!1);v.removeEventListener("webglcontextrestored",d,!1);sa.dispose();ka.dispose()};this.renderBufferImmediate=function(a,b,c){Z.initAttributes();var d=ca.get(a);a.hasPositions&&!d.position&&(d.position=F.createBuffer());a.hasNormals&&!d.normal&&(d.normal=F.createBuffer());a.hasUvs&&!d.uv&&(d.uv=F.createBuffer());a.hasColors&&!d.color&&(d.color=F.createBuffer()); +b=b.getAttributes();a.hasPositions&&(F.bindBuffer(F.ARRAY_BUFFER,d.position),F.bufferData(F.ARRAY_BUFFER,a.positionArray,F.DYNAMIC_DRAW),Z.enableAttribute(b.position),F.vertexAttribPointer(b.position,3,F.FLOAT,!1,0,0));if(a.hasNormals){F.bindBuffer(F.ARRAY_BUFFER,d.normal);if(!c.isMeshPhongMaterial&&!c.isMeshStandardMaterial&&!c.isMeshNormalMaterial&&!0===c.flatShading)for(var e=0,f=3*a.count;ee.matrixWorld.determinant();Z.setMaterial(d,g);var h=u(a,b,d,e);a=c.id+"_"+h.id+"_"+(!0===d.wireframe);var k=!1;a!==R&&(R=a,k=!0);e.morphTargetInfluences&&(xa.update(e,c,d,h),k=!0);var g=c.index,m=c.attributes.position;b=1;!0===d.wireframe&&(g=ra.getWireframeAttribute(c), b=2);a=ya;if(null!==g){var q=qa.get(g);a=za;a.setIndex(q)}if(k){k=void 0;if(c&&c.isInstancedBufferGeometry&&null===ia.get("ANGLE_instanced_arrays"))console.error("THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.");else{void 0===k&&(k=0);Z.initAttributes();var n=c.attributes,h=h.getAttributes(),l=d.defaultAttributeValues;for(J in h){var r=h[J];if(0<=r){var t=n[J];if(void 0!==t){var v=t.normalized,p=t.itemSize, -w=qa.get(t);if(void 0!==w){var A=w.buffer,y=w.type,w=w.bytesPerElement;if(t.isInterleavedBufferAttribute){var z=t.data,I=z.stride,t=t.offset;z&&z.isInstancedInterleavedBuffer?(Z.enableAttributeAndDivisor(r,z.meshPerAttribute),void 0===c.maxInstancedCount&&(c.maxInstancedCount=z.meshPerAttribute*z.count)):Z.enableAttribute(r);E.bindBuffer(E.ARRAY_BUFFER,A);E.vertexAttribPointer(r,p,y,v,I*w,(k*I+t)*w)}else t.isInstancedBufferAttribute?(Z.enableAttributeAndDivisor(r,t.meshPerAttribute),void 0===c.maxInstancedCount&& -(c.maxInstancedCount=t.meshPerAttribute*t.count)):Z.enableAttribute(r),E.bindBuffer(E.ARRAY_BUFFER,A),E.vertexAttribPointer(r,p,y,v,0,k*p*w)}}else if(void 0!==l&&(v=l[J],void 0!==v))switch(v.length){case 2:E.vertexAttrib2fv(r,v);break;case 3:E.vertexAttrib3fv(r,v);break;case 4:E.vertexAttrib4fv(r,v);break;default:E.vertexAttrib1fv(r,v)}}}Z.disableUnusedAttributes()}null!==g&&E.bindBuffer(E.ELEMENT_ARRAY_BUFFER,q.buffer)}q=0;null!==g?q=g.count:void 0!==m&&(q=m.count);g=c.drawRange.start*b;m=null!== -f?f.start*b:0;var J=Math.max(g,m);f=Math.max(0,Math.min(q,g+c.drawRange.count*b,m+(null!==f?f.count*b:Infinity))-1-J+1);if(0!==f){if(e.isMesh)if(!0===d.wireframe)Z.setLineWidth(d.wireframeLinewidth*(null===M?wa:1)),a.setMode(E.LINES);else switch(e.drawMode){case 0:a.setMode(E.TRIANGLES);break;case 1:a.setMode(E.TRIANGLE_STRIP);break;case 2:a.setMode(E.TRIANGLE_FAN)}else e.isLine?(d=d.linewidth,void 0===d&&(d=1),Z.setLineWidth(d*(null===M?wa:1)),e.isLineSegments?a.setMode(E.LINES):e.isLineLoop?a.setMode(E.LINE_LOOP): -a.setMode(E.LINE_STRIP)):e.isPoints&&a.setMode(E.POINTS);c&&c.isInstancedBufferGeometry?0=U.maxTextures&&console.warn("THREE.WebGLRenderer: Trying to use "+a+" texture units while this GPU supports only "+U.maxTextures);Y+=1;return a};this.setTexture2D= +w=qa.get(t);if(void 0!==w){var A=w.buffer,y=w.type,w=w.bytesPerElement;if(t.isInterleavedBufferAttribute){var z=t.data,I=z.stride,t=t.offset;z&&z.isInstancedInterleavedBuffer?(Z.enableAttributeAndDivisor(r,z.meshPerAttribute),void 0===c.maxInstancedCount&&(c.maxInstancedCount=z.meshPerAttribute*z.count)):Z.enableAttribute(r);F.bindBuffer(F.ARRAY_BUFFER,A);F.vertexAttribPointer(r,p,y,v,I*w,(k*I+t)*w)}else t.isInstancedBufferAttribute?(Z.enableAttributeAndDivisor(r,t.meshPerAttribute),void 0===c.maxInstancedCount&& +(c.maxInstancedCount=t.meshPerAttribute*t.count)):Z.enableAttribute(r),F.bindBuffer(F.ARRAY_BUFFER,A),F.vertexAttribPointer(r,p,y,v,0,k*p*w)}}else if(void 0!==l&&(v=l[J],void 0!==v))switch(v.length){case 2:F.vertexAttrib2fv(r,v);break;case 3:F.vertexAttrib3fv(r,v);break;case 4:F.vertexAttrib4fv(r,v);break;default:F.vertexAttrib1fv(r,v)}}}Z.disableUnusedAttributes()}null!==g&&F.bindBuffer(F.ELEMENT_ARRAY_BUFFER,q.buffer)}q=0;null!==g?q=g.count:void 0!==m&&(q=m.count);g=c.drawRange.start*b;m=null!== +f?f.start*b:0;var J=Math.max(g,m);f=Math.max(0,Math.min(q,g+c.drawRange.count*b,m+(null!==f?f.count*b:Infinity))-1-J+1);if(0!==f){if(e.isMesh)if(!0===d.wireframe)Z.setLineWidth(d.wireframeLinewidth*(null===N?wa:1)),a.setMode(F.LINES);else switch(e.drawMode){case 0:a.setMode(F.TRIANGLES);break;case 1:a.setMode(F.TRIANGLE_STRIP);break;case 2:a.setMode(F.TRIANGLE_FAN)}else e.isLine?(d=d.linewidth,void 0===d&&(d=1),Z.setLineWidth(d*(null===N?wa:1)),e.isLineSegments?a.setMode(F.LINES):e.isLineLoop?a.setMode(F.LINE_LOOP): +a.setMode(F.LINE_STRIP)):e.isPoints&&a.setMode(F.POINTS);c&&c.isInstancedBufferGeometry?0=T.maxTextures&&console.warn("THREE.WebGLRenderer: Trying to use "+a+" texture units while this GPU supports only "+T.maxTextures);Y+=1;return a};this.setTexture2D= function(){var a=!1;return function(b,c){b&&b.isWebGLRenderTarget&&(a||(console.warn("THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead."),a=!0),b=b.texture);ga.setTexture2D(b,c)}}();this.setTexture=function(){var a=!1;return function(b,c){a||(console.warn("THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead."),a=!0);ga.setTexture2D(b,c)}}();this.setTextureCube=function(){var a=!1;return function(b,c){b&&b.isWebGLRenderTargetCube&& -(a||(console.warn("THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead."),a=!0),b=b.texture);b&&b.isCubeTexture||Array.isArray(b.image)&&6===b.image.length?ga.setTextureCube(b,c):ga.setTextureCubeDynamic(b,c)}}();this.getRenderTarget=function(){return M};this.setRenderTarget=function(a){(M=a)&&void 0===da.get(a).__webglFramebuffer&&ga.setupRenderTarget(a);var b=null,c=!1;a?(b=da.get(a).__webglFramebuffer,a.isWebGLRenderTargetCube&&(b= -b[a.activeCubeFace],c=!0),jb.copy(a.viewport),X.copy(a.scissor),G=a.scissorTest):(jb.copy(ca).multiplyScalar(wa),X.copy(fa).multiplyScalar(wa),G=$e);R!==b&&(E.bindFramebuffer(E.FRAMEBUFFER,b),R=b);Z.viewport(jb);Z.scissor(X);Z.setScissorTest(G);c&&(c=da.get(a.texture),E.framebufferTexture2D(E.FRAMEBUFFER,E.COLOR_ATTACHMENT0,E.TEXTURE_CUBE_MAP_POSITIVE_X+a.activeCubeFace,c.__webglTexture,a.activeMipMapLevel))};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(a&&a.isWebGLRenderTarget){var g=da.get(a).__webglFramebuffer; -if(g){var h=!1;g!==R&&(E.bindFramebuffer(E.FRAMEBUFFER,g),h=!0);try{var k=a.texture,m=k.format,q=k.type;1023!==m&&pa.convert(m)!==E.getParameter(E.IMPLEMENTATION_COLOR_READ_FORMAT)?console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format."):1009===q||pa.convert(q)===E.getParameter(E.IMPLEMENTATION_COLOR_READ_TYPE)||1015===q&&(ia.get("OES_texture_float")||ia.get("WEBGL_color_buffer_float"))||1016===q&&ia.get("EXT_color_buffer_half_float")? -E.checkFramebufferStatus(E.FRAMEBUFFER)===E.FRAMEBUFFER_COMPLETE?0<=b&&b<=a.width-d&&0<=c&&c<=a.height-e&&E.readPixels(b,c,d,e,pa.convert(m),pa.convert(q),f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete."):console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.")}finally{h&&E.bindFramebuffer(E.FRAMEBUFFER,R)}}}else console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.")}} -function Nb(a,b){this.name="";this.color=new F(a);this.density=void 0!==b?b:2.5E-4}function Ob(a,b,c){this.name="";this.color=new F(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3}function vd(){x.call(this);this.type="Scene";this.overrideMaterial=this.fog=this.background=null;this.autoUpdate=!0}function de(a,b,c,d,e){x.call(this);this.lensFlares=[];this.positionScreen=new p;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)}function $a(a){N.call(this);this.type="SpriteMaterial"; -this.color=new F(16777215);this.map=null;this.rotation=0;this.lights=this.fog=!1;this.setValues(a)}function Bc(a){x.call(this);this.type="Sprite";this.material=void 0!==a?a:new $a}function Cc(){x.call(this);this.type="LOD";Object.defineProperties(this,{levels:{enumerable:!0,value:[]}})}function Dc(a,b){a=a||[];this.bones=a.slice(0);this.boneMatrices=new Float32Array(16*this.bones.length);if(void 0===b)this.calculateInverses();else if(this.bones.length===b.length)this.boneInverses=b.slice(0);else for(console.warn("THREE.Skeleton boneInverses is the wrong length."), -this.boneInverses=[],a=0,b=this.bones.length;ac;c++){var n=q[h[c]];var u=q[h[(c+1)%3]];f[0]=Math.min(n,u);f[1]=Math.max(n,u);n=f[0]+","+f[1];void 0===g[n]&&(g[n]={index1:f[0],index2:f[1]})}}for(n in g)m=g[n],h=a.vertices[m.index1],b.push(h.x,h.y,h.z),h=a.vertices[m.index2],b.push(h.x,h.y,h.z)}else if(a&&a.isBufferGeometry){var h=new p;if(null!== +(a||(console.warn("THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead."),a=!0),b=b.texture);b&&b.isCubeTexture||Array.isArray(b.image)&&6===b.image.length?ga.setTextureCube(b,c):ga.setTextureCubeDynamic(b,c)}}();this.getRenderTarget=function(){return N};this.setRenderTarget=function(a){(N=a)&&void 0===ca.get(a).__webglFramebuffer&&ga.setupRenderTarget(a);var b=null,c=!1;a?(b=ca.get(a).__webglFramebuffer,a.isWebGLRenderTargetCube&&(b= +b[a.activeCubeFace],c=!0),nb.copy(a.viewport),X.copy(a.scissor),G=a.scissorTest):(nb.copy(da).multiplyScalar(wa),X.copy(fa).multiplyScalar(wa),G=$e);M!==b&&(F.bindFramebuffer(F.FRAMEBUFFER,b),M=b);Z.viewport(nb);Z.scissor(X);Z.setScissorTest(G);c&&(c=ca.get(a.texture),F.framebufferTexture2D(F.FRAMEBUFFER,F.COLOR_ATTACHMENT0,F.TEXTURE_CUBE_MAP_POSITIVE_X+a.activeCubeFace,c.__webglTexture,a.activeMipMapLevel))};this.readRenderTargetPixels=function(a,b,c,d,e,f){if(a&&a.isWebGLRenderTarget){var g=ca.get(a).__webglFramebuffer; +if(g){var h=!1;g!==M&&(F.bindFramebuffer(F.FRAMEBUFFER,g),h=!0);try{var k=a.texture,m=k.format,q=k.type;1023!==m&&pa.convert(m)!==F.getParameter(F.IMPLEMENTATION_COLOR_READ_FORMAT)?console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format."):1009===q||pa.convert(q)===F.getParameter(F.IMPLEMENTATION_COLOR_READ_TYPE)||1015===q&&(ia.get("OES_texture_float")||ia.get("WEBGL_color_buffer_float"))||1016===q&&ia.get("EXT_color_buffer_half_float")? +F.checkFramebufferStatus(F.FRAMEBUFFER)===F.FRAMEBUFFER_COMPLETE?0<=b&&b<=a.width-d&&0<=c&&c<=a.height-e&&F.readPixels(b,c,d,e,pa.convert(m),pa.convert(q),f):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete."):console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.")}finally{h&&F.bindFramebuffer(F.FRAMEBUFFER,M)}}}else console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.")}} +function Pb(a,b){this.name="";this.color=new H(a);this.density=void 0!==b?b:2.5E-4}function Qb(a,b,c){this.name="";this.color=new H(a);this.near=void 0!==b?b:1;this.far=void 0!==c?c:1E3}function vd(){x.call(this);this.type="Scene";this.overrideMaterial=this.fog=this.background=null;this.autoUpdate=!0}function de(a,b,c,d,e){x.call(this);this.lensFlares=[];this.positionScreen=new p;this.customUpdateCallback=void 0;void 0!==a&&this.add(a,b,c,d,e)}function hb(a){P.call(this);this.type="SpriteMaterial"; +this.color=new H(16777215);this.map=null;this.rotation=0;this.lights=this.fog=!1;this.setValues(a)}function Cc(a){x.call(this);this.type="Sprite";this.material=void 0!==a?a:new hb}function Dc(){x.call(this);this.type="LOD";Object.defineProperties(this,{levels:{enumerable:!0,value:[]}})}function Ec(a,b){a=a||[];this.bones=a.slice(0);this.boneMatrices=new Float32Array(16*this.bones.length);if(void 0===b)this.calculateInverses();else if(this.bones.length===b.length)this.boneInverses=b.slice(0);else for(console.warn("THREE.Skeleton boneInverses is the wrong length."), +this.boneInverses=[],a=0,b=this.bones.length;ac;c++){var n=q[h[c]];var u=q[h[(c+1)%3]];f[0]=Math.min(n,u);f[1]=Math.max(n,u);n=f[0]+","+f[1];void 0===g[n]&&(g[n]={index1:f[0],index2:f[1]})}}for(n in g)m=g[n],h=a.vertices[m.index1],b.push(h.x,h.y,h.z),h=a.vertices[m.index2],b.push(h.x,h.y,h.z)}else if(a&&a.isBufferGeometry){var h=new p;if(null!== a.index){k=a.attributes.position;q=a.index;var l=a.groups;0===l.length&&(l=[{start:0,count:q.count,materialIndex:0}]);a=0;for(e=l.length;ac;c++)n=q.getX(m+c),u=q.getX(m+(c+1)%3),f[0]=Math.min(n,u),f[1]=Math.max(n,u),n=f[0]+","+f[1],void 0===g[n]&&(g[n]={index1:f[0],index2:f[1]});for(n in g)m=g[n],h.fromBufferAttribute(k,m.index1),b.push(h.x,h.y,h.z),h.fromBufferAttribute(k,m.index2),b.push(h.x,h.y,h.z)}else for(k=a.attributes.position, -m=0,d=k.count/3;mc;c++)g=3*m+c,h.fromBufferAttribute(k,g),b.push(h.x,h.y,h.z),g=3*m+(c+1)%3,h.fromBufferAttribute(k,g),b.push(h.x,h.y,h.z)}this.addAttribute("position",new B(b,3))}function Gc(a,b,c){L.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};this.fromBufferGeometry(new Sb(a,b,c));this.mergeVertices()}function Sb(a,b,c){C.call(this);this.type="ParametricBufferGeometry";this.parameters={func:a,slices:b,stacks:c};var d=[],e=[],f=[],g=[],h= +m=0,d=k.count/3;mc;c++)g=3*m+c,h.fromBufferAttribute(k,g),b.push(h.x,h.y,h.z),g=3*m+(c+1)%3,h.fromBufferAttribute(k,g),b.push(h.x,h.y,h.z)}this.addAttribute("position",new B(b,3))}function Hc(a,b,c){L.call(this);this.type="ParametricGeometry";this.parameters={func:a,slices:b,stacks:c};this.fromBufferGeometry(new Ub(a,b,c));this.mergeVertices()}function Ub(a,b,c){E.call(this);this.type="ParametricBufferGeometry";this.parameters={func:a,slices:b,stacks:c};var d=[],e=[],f=[],g=[],h= new p,k=new p,m=new p,q=new p,n=new p,u,l,t=b+1;for(u=0;u<=c;u++){var v=u/c;for(l=0;l<=b;l++){var w=l/b,k=a(w,v,k);e.push(k.x,k.y,k.z);0<=w-1E-5?(m=a(w-1E-5,v,m),q.subVectors(k,m)):(m=a(w+1E-5,v,m),q.subVectors(m,k));0<=v-1E-5?(m=a(w,v-1E-5,m),n.subVectors(k,m)):(m=a(w,v+1E-5,m),n.subVectors(m,k));h.crossVectors(q,n).normalize();f.push(h.x,h.y,h.z);g.push(w,v)}}for(u=0;ud&&1===a.x&&(k[b]=a.x-1);0===c.x&&0===c.z&&(k[b]=d/2/Math.PI+.5)}C.call(this);this.type="PolyhedronBufferGeometry"; +new B(e,3));this.addAttribute("normal",new B(f,3));this.addAttribute("uv",new B(g,2))}function Ic(a,b,c,d){L.call(this);this.type="PolyhedronGeometry";this.parameters={vertices:a,indices:b,radius:c,detail:d};this.fromBufferGeometry(new ja(a,b,c,d));this.mergeVertices()}function ja(a,b,c,d){function e(a){h.push(a.x,a.y,a.z)}function f(b,c){b*=3;c.x=a[b+0];c.y=a[b+1];c.z=a[b+2]}function g(a,b,c,d){0>d&&1===a.x&&(k[b]=a.x-1);0===c.x&&0===c.z&&(k[b]=d/2/Math.PI+.5)}E.call(this);this.type="PolyhedronBufferGeometry"; this.parameters={vertices:a,indices:b,radius:c,detail:d};c=c||1;d=d||0;var h=[],k=[];(function(a){for(var c=new p,d=new p,g=new p,h=0;he&&(.2>b&&(k[a+0]+=1),.2>c&&(k[a+2]+=1),.2>d&&(k[a+4]+=1))})();this.addAttribute("position",new B(h,3));this.addAttribute("normal",new B(h.slice(),3));this.addAttribute("uv",new B(k,2));0===d?this.computeVertexNormals(): -this.normalizeNormals()}function Ic(a,b){L.call(this);this.type="TetrahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Tb(a,b));this.mergeVertices()}function Tb(a,b){sa.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],a,b);this.type="TetrahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Jc(a,b){L.call(this);this.type="OctahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new qb(a,b));this.mergeVertices()} -function qb(a,b){sa.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],a,b);this.type="OctahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Kc(a,b){L.call(this);this.type="IcosahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Ub(a,b));this.mergeVertices()}function Ub(a,b){var c=(1+Math.sqrt(5))/2;sa.call(this,[-1,c,0,1,c,0,-1,-c,0,1,-c,0,0,-1,c,0,1,c,0,-1,-c,0,1,-c,c,0,-1,c,0,1,-c,0,-1,-c,0,1],[0,11, -5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],a,b);this.type="IcosahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Lc(a,b){L.call(this);this.type="DodecahedronGeometry";this.parameters={radius:a,detail:b};this.fromBufferGeometry(new Vb(a,b));this.mergeVertices()}function Vb(a,b){var c=(1+Math.sqrt(5))/2,d=1/c;sa.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-d,-c,0,-d,c,0, -d,-c,0,d,c,-d,-c,0,-d,c,0,d,-c,0,d,c,0,-c,0,-d,c,0,-d,-c,0,d,c,0,d],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],a,b);this.type="DodecahedronBufferGeometry";this.parameters={radius:a,detail:b}}function Mc(a,b,c,d,e,f){L.call(this);this.type="TubeGeometry";this.parameters={path:a, -tubularSegments:b,radius:c,radialSegments:d,closed:e};void 0!==f&&console.warn("THREE.TubeGeometry: taper has been removed.");a=new Wb(a,b,c,d,e);this.tangents=a.tangents;this.normals=a.normals;this.binormals=a.binormals;this.fromBufferGeometry(a);this.mergeVertices()}function Wb(a,b,c,d,e){function f(e){q=a.getPointAt(e/b,q);var f=g.normals[e];e=g.binormals[e];for(l=0;l<=d;l++){var m=l/d*Math.PI*2,n=Math.sin(m),m=-Math.cos(m);k.x=m*f.x+n*e.x;k.y=m*f.y+n*e.y;k.z=m*f.z+n*e.z;k.normalize();t.push(k.x, -k.y,k.z);h.x=q.x+c*k.x;h.y=q.y+c*k.y;h.z=q.z+c*k.z;r.push(h.x,h.y,h.z)}}C.call(this);this.type="TubeBufferGeometry";this.parameters={path:a,tubularSegments:b,radius:c,radialSegments:d,closed:e};b=b||64;c=c||1;d=d||8;e=e||!1;var g=a.computeFrenetFrames(b,e);this.tangents=g.tangents;this.normals=g.normals;this.binormals=g.binormals;var h=new p,k=new p,m=new D,q=new p,n,l,r=[],t=[],v=[],w=[];for(n=0;n=b;e-=d)f=cf(e,a[e],a[e+1],f);f&&rb(f,f.next)&&(Pc(f),f=f.next);return f}function Qc(a,b){if(!a)return a;b||(b=a);do{var c=!1;if(a.steiner||!rb(a,a.next)&&0!==ra(a.prev,a,a.next))a=a.next;else{Pc(a);a=b=a.prev; -if(a===a.next)break;c=!0}}while(c||a!==b);return b}function Rc(a,b,c,d,e,f,g){if(a){if(!g&&f){var h=a,k=h;do null===k.z&&(k.z=fe(k.x,k.y,d,e,f)),k.prevZ=k.prev,k=k.nextZ=k.next;while(k!==h);k.prevZ.nextZ=null;k.prevZ=null;var h=k,m,q,n,l,r=1;do{k=h;var t=h=null;for(q=0;k;){q++;var p=k;for(m=n=0;mn.x?q.x>r.x?q.x:r.x:n.x>r.x?n.x:r.x,I=q.y>n.y?q.y>r.y?q.y:r.y:n.y>r.y?n.y:r.y;m=fe(q.x=m;){if(w!==t.prev&&w!==t.next&&zd(q.x,q.y,n.x,n.y,r.x, -r.y,w.x,w.y)&&0<=ra(w.prev,w,w.next)){t=!1;break a}w=w.prevZ}t=!0}}else a:if(t=a,q=t.prev,n=t,r=t.next,0<=ra(q,n,r))t=!1;else{for(m=t.next.next;m!==t.prev;){if(zd(q.x,q.y,n.x,n.y,r.x,r.y,m.x,m.y)&&0<=ra(m.prev,m,m.next)){t=!1;break a}m=m.next}t=!0}if(t)b.push(k.i/c),b.push(a.i/c),b.push(p.i/c),Pc(a),h=a=p.next;else if(a=p,a===h){if(!g)Rc(Qc(a),b,c,d,e,f,1);else if(1===g){g=b;h=c;k=a;do p=k.prev,t=k.next.next,!rb(p,t)&&df(p,k,k.next,t)&&Sc(p,t)&&Sc(t,p)&&(g.push(p.i/h),g.push(k.i/h),g.push(t.i/h), -Pc(k),Pc(k.next),k=a=t),k=k.next;while(k!==a);a=k;Rc(a,b,c,d,e,f,2)}else if(2===g)a:{g=a;do{for(h=g.next.next;h!==g.prev;){if(k=g.i!==h.i){k=g;p=h;if(t=k.next.i!==p.i&&k.prev.i!==p.i){b:{t=k;do{if(t.i!==k.i&&t.next.i!==k.i&&t.i!==p.i&&t.next.i!==p.i&&df(t,t.next,k,p)){t=!0;break b}t=t.next}while(t!==k);t=!1}t=!t}if(t=t&&Sc(k,p)&&Sc(p,k)){t=k;q=!1;n=(k.x+p.x)/2;p=(k.y+p.y)/2;do t.y>p!==t.next.y>p&&t.next.y!==t.y&&n<(t.next.x-t.x)*(p-t.y)/(t.next.y-t.y)+t.x&&(q=!q),t=t.next;while(t!==k);t=q}k=t}if(k){a= -ef(g,h);g=Qc(g,g.next);a=Qc(a,a.next);Rc(g,b,c,d,e,f);Rc(a,b,c,d,e,f);break a}h=h.next}g=g.next}while(g!==a)}break}}}}function Gg(a,b){return a.x-b.x}function Hg(a,b){var c=b,d=a.x,e=a.y,f=-Infinity;do{if(e<=c.y&&e>=c.next.y&&c.next.y!==c.y){var g=c.x+(e-c.y)*(c.next.x-c.x)/(c.next.y-c.y);if(g<=d&&g>f){f=g;if(g===d){if(e===c.y)return c;if(e===c.next.y)return c.next}var h=c.x=c.x&&c.x>=g&&d!==c.x&&zd(eh.x)&&Sc(c,a)&&(h=c,m=q)),c=c.next;return h}function fe(a,b,c,d,e){a=32767*(a-c)*e;b=32767*(b-d)*e;a=(a|a<<8)&16711935;a=(a|a<<4)&252645135;a=(a|a<<2)&858993459;b=(b|b<<8)&16711935;b=(b|b<<4)&252645135;b=(b|b<<2)&858993459;return(a|a<<1)&1431655765|((b|b<<1)&1431655765)<<1}function Ig(a){var b=a,c=a;do b.xra(a.prev,a,a.next)?0<=ra(a,b,a.next)&&0<=ra(a,a.prev,b):0>ra(a,b,a.prev)||0>ra(a,a.next,b)}function ef(a,b){var c=new ge(a.i,a.x,a.y),d=new ge(b.i,b.x,b.y),e=a.next,f=b.prev; -a.next=b;b.prev=a;c.next=e;e.prev=c;d.next=c;c.prev=d;f.next=d;d.prev=f;return d}function cf(a,b,c,d){a=new ge(a,b,c);d?(a.next=d.next,a.prev=d,d.next.prev=a,d.next=a):(a.prev=a,a.next=a);return a}function Pc(a){a.next.prev=a.prev;a.prev.next=a.next;a.prevZ&&(a.prevZ.nextZ=a.nextZ);a.nextZ&&(a.nextZ.prevZ=a.prevZ)}function ge(a,b,c){this.i=a;this.x=b;this.y=c;this.nextZ=this.prevZ=this.z=this.next=this.prev=null;this.steiner=!1}function ab(a,b){L.call(this);this.type="ExtrudeGeometry";this.parameters= -{shapes:a,options:b};this.fromBufferGeometry(new Ja(a,b));this.mergeVertices()}function Ja(a,b){"undefined"!==typeof a&&(C.call(this),this.type="ExtrudeBufferGeometry",a=Array.isArray(a)?a:[a],this.addShapeList(a,b),this.computeVertexNormals())}function Tc(a,b){L.call(this);this.type="TextGeometry";this.parameters={text:a,parameters:b};this.fromBufferGeometry(new Zb(a,b));this.mergeVertices()}function Zb(a,b){b=b||{};var c=b.font;if(!c||!c.isFont)return console.error("THREE.TextGeometry: font parameter is not an instance of THREE.Font."), -new L;a=c.generateShapes(a,b.size,b.curveSegments);b.amount=void 0!==b.height?b.height:50;void 0===b.bevelThickness&&(b.bevelThickness=10);void 0===b.bevelSize&&(b.bevelSize=8);void 0===b.bevelEnabled&&(b.bevelEnabled=!1);Ja.call(this,a,b);this.type="TextBufferGeometry"}function Uc(a,b,c,d,e,f,g){L.call(this);this.type="SphereGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};this.fromBufferGeometry(new sb(a,b,c,d,e,f,g));this.mergeVertices()} -function sb(a,b,c,d,e,f,g){C.call(this);this.type="SphereBufferGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};a=a||1;b=Math.max(3,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;f=void 0!==f?f:0;g=void 0!==g?g:Math.PI;var h=f+g,k,m,q=0,n=[],l=new p,r=new p,t=[],v=[],w=[],z=[];for(m=0;m<=c;m++){var y=[],I=m/c;for(k=0;k<=b;k++){var A=k/b;l.x=-a*Math.cos(d+A*e)*Math.sin(f+I*g);l.y=a*Math.cos(f+ -I*g);l.z=a*Math.sin(d+A*e)*Math.sin(f+I*g);v.push(l.x,l.y,l.z);r.set(l.x,l.y,l.z).normalize();w.push(r.x,r.y,r.z);z.push(A,1-I);y.push(q++)}n.push(y)}for(m=0;mq;q++){var n=m[f[q]];var l=m[f[(q+1)%3]];d[0]=Math.min(n,l);d[1]=Math.max(n,l);n=d[0]+","+ -d[1];void 0===e[n]?e[n]={index1:d[0],index2:d[1],face1:h,face2:void 0}:e[n].face2=h}for(n in e)if(d=e[n],void 0===d.face2||g[d.face1].normal.dot(g[d.face2].normal)<=b)f=a[d.index1],c.push(f.x,f.y,f.z),f=a[d.index2],c.push(f.x,f.y,f.z);this.addAttribute("position",new B(c,3))}function tb(a,b,c,d,e,f,g,h){L.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a,radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:h};this.fromBufferGeometry(new Ua(a, -b,c,d,e,f,g,h));this.mergeVertices()}function Ua(a,b,c,d,e,f,g,h){function k(c){var e,f=new D,k=new p,u=0,v=!0===c?a:b,y=!0===c?1:-1;var x=t;for(e=1;e<=d;e++)n.push(0,w*y,0),l.push(0,y,0),r.push(.5,.5),t++;var B=t;for(e=0;e<=d;e++){var C=e/d*h+g,F=Math.cos(C),C=Math.sin(C);k.x=v*C;k.y=w*y;k.z=v*F;n.push(k.x,k.y,k.z);l.push(0,y,0);f.x=.5*F+.5;f.y=.5*C*y+.5;r.push(f.x,f.y);t++}for(e=0;ethis.duration&&this.resetDuration();this.optimize()}function Pd(a){this.manager= -void 0!==a?a:ja;this.textures={}}function ke(a){this.manager=void 0!==a?a:ja}function jc(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}}function le(a){"boolean"===typeof a&&(console.warn("THREE.JSONLoader: showStatus parameter has been removed from constructor."),a=void 0);this.manager=void 0!==a?a:ja;this.withCredentials=!1}function gf(a){this.manager=void 0!==a?a:ja;this.texturePath=""}function me(a){"undefined"===typeof createImageBitmap&&console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported."); -"undefined"===typeof fetch&&console.warn("THREE.ImageBitmapLoader: fetch() not supported.");this.manager=void 0!==a?a:ja;this.options=void 0}function hf(a,b,c,d,e){b=.5*(d-b);e=.5*(e-c);var f=a*a;return(2*c-2*d+b+e)*a*f+(-3*c+3*d-2*b-e)*f+b*a+c}function cd(a,b,c,d){var e=1-a;return e*e*b+2*(1-a)*a*c+a*a*d}function dd(a,b,c,d,e){var f=1-a,g=1-a;return f*f*f*b+3*g*g*a*c+3*(1-a)*a*a*d+a*a*a*e}function P(){this.type="Curve";this.arcLengthDivisions=200}function Ma(a,b){P.call(this);this.type="LineCurve"; -this.v1=a||new D;this.v2=b||new D}function Ab(){P.call(this);this.type="CurvePath";this.curves=[];this.autoClose=!1}function Pa(a,b,c,d,e,f,g,h){P.call(this);this.type="EllipseCurve";this.aX=a||0;this.aY=b||0;this.xRadius=c||1;this.yRadius=d||1;this.aStartAngle=e||0;this.aEndAngle=f||2*Math.PI;this.aClockwise=g||!1;this.aRotation=h||0}function bb(a){P.call(this);this.type="SplineCurve";this.points=a||[]}function cb(a,b,c,d){P.call(this);this.type="CubicBezierCurve";this.v0=a||new D;this.v1=b||new D; -this.v2=c||new D;this.v3=d||new D}function db(a,b,c){P.call(this);this.type="QuadraticBezierCurve";this.v0=a||new D;this.v1=b||new D;this.v2=c||new D}function eb(a){Ab.call(this);this.type="Path";this.currentPoint=new D;a&&this.setFromPoints(a)}function Bb(a){eb.call(this,a);this.type="Shape";this.holes=[]}function ne(){this.type="ShapePath";this.subPaths=[];this.currentPath=null}function oe(a){this.type="Font";this.data=a}function jf(a){this.manager=void 0!==a?a:ja}function pe(a){this.manager=void 0!== -a?a:ja}function kf(){this.type="StereoCamera";this.aspect=1;this.eyeSep=.064;this.cameraL=new ba;this.cameraL.layers.enable(1);this.cameraL.matrixAutoUpdate=!1;this.cameraR=new ba;this.cameraR.layers.enable(2);this.cameraR.matrixAutoUpdate=!1}function ed(a,b,c){x.call(this);this.type="CubeCamera";var d=new ba(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new p(1,0,0));this.add(d);var e=new ba(90,1,a,b);e.up.set(0,-1,0);e.lookAt(new p(-1,0,0));this.add(e);var f=new ba(90,1,a,b);f.up.set(0,0,1);f.lookAt(new p(0, -1,0));this.add(f);var g=new ba(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new p(0,-1,0));this.add(g);var h=new ba(90,1,a,b);h.up.set(0,-1,0);h.lookAt(new p(0,0,1));this.add(h);var k=new ba(90,1,a,b);k.up.set(0,-1,0);k.lookAt(new p(0,0,-1));this.add(k);this.renderTarget=new Hb(c,c,{format:1022,magFilter:1006,minFilter:1006});this.renderTarget.texture.name="CubeCamera";this.update=function(a,b){null===this.parent&&this.updateMatrixWorld();var c=this.renderTarget,m=c.texture.generateMipmaps;c.texture.generateMipmaps= -!1;c.activeCubeFace=0;a.render(b,d,c);c.activeCubeFace=1;a.render(b,e,c);c.activeCubeFace=2;a.render(b,f,c);c.activeCubeFace=3;a.render(b,g,c);c.activeCubeFace=4;a.render(b,h,c);c.texture.generateMipmaps=m;c.activeCubeFace=5;a.render(b,k,c);a.setRenderTarget(null)};this.clear=function(a,b,c,d){for(var e=this.renderTarget,f=0;6>f;f++)e.activeCubeFace=f,a.setRenderTarget(e),a.clear(b,c,d);a.setRenderTarget(null)}}function qe(){x.call(this);this.type="AudioListener";this.context=re.getContext();this.gain= -this.context.createGain();this.gain.connect(this.context.destination);this.filter=null}function kc(a){x.call(this);this.type="Audio";this.context=a.context;this.gain=this.context.createGain();this.gain.connect(a.getInput());this.autoplay=!1;this.buffer=null;this.loop=!1;this.offset=this.startTime=0;this.playbackRate=1;this.isPlaying=!1;this.hasPlaybackControl=!0;this.sourceType="empty";this.filters=[]}function se(a){kc.call(this,a);this.panner=this.context.createPanner();this.panner.connect(this.gain)} -function te(a,b){this.analyser=a.context.createAnalyser();this.analyser.fftSize=void 0!==b?b:2048;this.data=new Uint8Array(this.analyser.frequencyBinCount);a.getOutput().connect(this.analyser)}function ue(a,b,c){this.binding=a;this.valueSize=c;a=Float64Array;switch(b){case "quaternion":b=this._slerp;break;case "string":case "bool":a=Array;b=this._select;break;default:b=this._lerp}this.buffer=new a(4*c);this._mixBufferRegion=b;this.referenceCount=this.useCount=this.cumulativeWeight=0}function lf(a, -b,c){c=c||ga.parseTrackName(b);this._targetGroup=a;this._bindings=a.subscribe_(b,c)}function ga(a,b,c){this.path=b;this.parsedPath=c||ga.parseTrackName(b);this.node=ga.findNode(a,this.parsedPath.nodeName)||a;this.rootNode=a}function mf(){this.uuid=O.generateUUID();this._objects=Array.prototype.slice.call(arguments);this.nCachedObjects_=0;var a={};this._indicesByUUID=a;for(var b=0,c=arguments.length;b!==c;++b)a[arguments[b].uuid]=b;this._paths=[];this._parsedPaths=[];this._bindings=[];this._bindingsIndicesByPath= -{};var d=this;this.stats={objects:{get total(){return d._objects.length},get inUse(){return this.total-d.nCachedObjects_}},get bindingsPerObject(){return d._bindings.length}}}function nf(a,b,c){this._mixer=a;this._clip=b;this._localRoot=c||null;a=b.tracks;b=a.length;c=Array(b);for(var d={endingStart:2400,endingEnd:2400},e=0;e!==b;++e){var f=a[e].createInterpolant(null);c[e]=f;f.settings=d}this._interpolantSettings=d;this._interpolants=c;this._propertyBindings=Array(b);this._weightInterpolant=this._timeScaleInterpolant= -this._byClipCacheIndex=this._cacheIndex=null;this.loop=2201;this._loopCount=-1;this._startTime=null;this.time=0;this._effectiveWeight=this.weight=this._effectiveTimeScale=this.timeScale=1;this.repetitions=Infinity;this.paused=!1;this.enabled=!0;this.clampWhenFinished=!1;this.zeroSlopeAtEnd=this.zeroSlopeAtStart=!0}function ve(a){this._root=a;this._initMemoryManager();this.time=this._accuIndex=0;this.timeScale=1}function Qd(a,b){"string"===typeof a&&(console.warn("THREE.Uniform: Type parameter is no longer needed."), -a=b);this.value=a}function we(){C.call(this);this.type="InstancedBufferGeometry";this.maxInstancedCount=void 0}function xe(a,b,c,d){this.uuid=O.generateUUID();this.data=a;this.itemSize=b;this.offset=c;this.normalized=!0===d}function lc(a,b){this.uuid=O.generateUUID();this.array=a;this.stride=b;this.count=void 0!==a?a.length/b:0;this.dynamic=!1;this.updateRange={offset:0,count:-1};this.onUploadCallback=function(){};this.version=0}function ye(a,b,c){lc.call(this,a,b);this.meshPerAttribute=c||1}function ze(a, -b,c){R.call(this,a,b);this.meshPerAttribute=c||1}function of(a,b,c,d){this.ray=new ob(a,b);this.near=c||0;this.far=d||Infinity;this.params={Mesh:{},Line:{},LOD:{},Points:{threshold:1},Sprite:{}};Object.defineProperties(this.params,{PointCloud:{get:function(){console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points.");return this.Points}}})}function pf(a,b){return a.distance-b.distance}function Ae(a,b,c,d){if(!1!==a.visible&&(a.raycast(b,c),!0===d)){a=a.children;d=0;for(var e= -a.length;dc;c++,d++){var e=c/32*Math.PI*2,f=d/32*Math.PI*2;b.push(Math.cos(e),Math.sin(e),1,Math.cos(f),Math.sin(f),1)}a.addAttribute("position",new B(b,3));b=new W({fog:!1});this.cone=new X(a,b);this.add(this.cone);this.update()}function tf(a){var b=[];a&&a.isBone&&b.push(a);for(var c=0;ca?-1:0b;b++)a[b]=(16>b?"0":"")+b.toString(16).toUpperCase(); -return function(){var b=4294967295*Math.random()|0,d=4294967295*Math.random()|0,e=4294967295*Math.random()|0,f=4294967295*Math.random()|0;return a[b&255]+a[b>>8&255]+a[b>>16&255]+a[b>>24&255]+"-"+a[d&255]+a[d>>8&255]+"-"+a[d>>16&15|64]+a[d>>24&255]+"-"+a[e&63|128]+a[e>>8&255]+"-"+a[e>>16&255]+a[e>>24&255]+a[f&255]+a[f>>8&255]+a[f>>16&255]+a[f>>24&255]}}(),clamp:function(a,b,c){return Math.max(b,Math.min(c,a))},euclideanModulo:function(a,b){return(a%b+b)%b},mapLinear:function(a,b,c,d,e){return d+(a- -b)*(e-d)/(c-b)},lerp:function(a,b,c){return(1-c)*a+c*b},smoothstep:function(a,b,c){if(a<=b)return 0;if(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)},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(a){return a*O.DEG2RAD},radToDeg:function(a){return a* -O.RAD2DEG},isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},ceilPowerOfTwo:function(a){return Math.pow(2,Math.ceil(Math.log(a)/Math.LN2))},floorPowerOfTwo:function(a){return Math.pow(2,Math.floor(Math.log(a)/Math.LN2))}};Object.defineProperties(D.prototype,{width:{get:function(){return this.x},set:function(a){this.x=a}},height:{get:function(){return this.y},set:function(a){this.y=a}}});Object.assign(D.prototype,{isVector2:!0,set:function(a,b){this.x=a;this.y=b;return this},setScalar:function(a){this.y= -this.x=a;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);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y)},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},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},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;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},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){return this.multiplyScalar(1/a)},applyMatrix3:function(a){var b=this.x,c=this.y;a=a.elements;this.x=a[0]*b+a[3]*c+a[6];this.y= -a[1]*b+a[4]*c+a[7];return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));return this},clampScalar:function(){var a=new D,b=new D;return function(c,d){a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c|| -1).multiplyScalar(Math.max(a,Math.min(b,c)))},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)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length()||1)},angle:function(){var a=Math.atan2(this.y,this.x);0>a&&(a+=2*Math.PI);return a},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},manhattanDistanceTo:function(a){return Math.abs(this.x- -a.x)+Math.abs(this.y-a.y)},setLength:function(a){return this.normalize().multiplyScalar(a)},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){return this.subVectors(b,a).multiplyScalar(c).add(a)},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},fromBufferAttribute:function(a, -b,c){void 0!==c&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);return this},rotateAround:function(a,b){var c=Math.cos(b);b=Math.sin(b);var d=this.x-a.x,e=this.y-a.y;this.x=d*c-e*b+a.x;this.y=d*b+e*c+a.y;return this}});Object.assign(H.prototype,{isMatrix4:!0,set:function(a,b,c,d,e,f,g,h,k,m,q,l,u,r,t,p){var n=this.elements;n[0]=a;n[4]=b;n[8]=c;n[12]=d;n[1]=e;n[5]=f;n[9]=g;n[13]=h;n[2]=k;n[6]=m;n[10]=q;n[14]=l;n[3]=u;n[7]=r;n[11]= -t;n[15]=p;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},clone:function(){return(new H).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return this},copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a, -b,c){a.setFromMatrixColumn(this,0);b.setFromMatrixColumn(this,1);c.setFromMatrixColumn(this,2);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(){var a=new p;return function(b){var c=this.elements,d=b.elements,e=1/a.setFromMatrixColumn(b,0).length(),f=1/a.setFromMatrixColumn(b,1).length();b=1/a.setFromMatrixColumn(b,2).length();c[0]=d[0]*e;c[1]=d[1]*e;c[2]=d[2]*e;c[4]=d[4]*f;c[5]=d[5]*f;c[6]=d[6]*f;c[8]=d[8]*b; -c[9]=d[9]*b;c[10]=d[10]*b;return this}}(),makeRotationFromEuler:function(a){a&&a.isEuler||console.error("THREE.Matrix4: .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){var k=f*h;var m=f*e;var q=c*h;a=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=m+q*d;b[5]=k-a*d;b[9]=-c*g;b[2]=a-k*d;b[6]=q+m*d;b[10]=f*g}else"YXZ"===a.order?(k=g* -h,m=g*e,q=d*h,a=d*e,b[0]=k+a*c,b[4]=q*c-m,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=m*c-q,b[6]=a+k*c,b[10]=f*g):"ZXY"===a.order?(k=g*h,m=g*e,q=d*h,a=d*e,b[0]=k-a*c,b[4]=-f*e,b[8]=q+m*c,b[1]=m+q*c,b[5]=f*h,b[9]=a-k*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(k=f*h,m=f*e,q=c*h,a=c*e,b[0]=g*h,b[4]=q*d-m,b[8]=k*d+a,b[1]=g*e,b[5]=a*d+k,b[9]=m*d-q,b[2]=-d,b[6]=c*g,b[10]=f*g):"YZX"===a.order?(k=f*g,m=f*d,q=c*g,a=c*d,b[0]=g*h,b[4]=a-k*e,b[8]=q*e+m,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=m*e+q,b[10]=k-a* -e):"XZY"===a.order&&(k=f*g,m=f*d,q=c*g,a=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=k*e+a,b[5]=f*h,b[9]=m*e-q,b[2]=q*e-m,b[6]=c*h,b[10]=a*e+k);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},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 m=c*h,c=c*k,q=d*h,d=d*k,e=e*k,g=f*g,h=f*h,f=f*k;b[0]=1-(q+e);b[4]=m-f;b[8]=c+h;b[1]=m+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+q);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 p,b=new p,c=new p;return function(d,e,f){var g=this.elements;c.subVectors(d,e);0===c.lengthSq()&&(c.z=1);c.normalize();a.crossVectors(f,c);0===a.lengthSq()&&(1===Math.abs(f.z)?c.x+=1E-4:c.z+=1E-4,c.normalize(),a.crossVectors(f,c));a.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?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."), -this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements;b=this.elements;a=c[0];var e=c[4],f=c[8],g=c[12],h=c[1],k=c[5],m=c[9],q=c[13],n=c[2],l=c[6],r=c[10],t=c[14],p=c[3],w=c[7],z=c[11],c=c[15],y=d[0],I=d[4],A=d[8],J=d[12],x=d[1],B=d[5],D=d[9],C=d[13],F=d[2],H=d[6],K=d[10],S=d[14],L=d[3],M=d[7],N=d[11],d=d[15];b[0]=a*y+e*x+f*F+g*L;b[4]=a*I+e*B+f*H+g*M;b[8]=a*A+e*D+f*K+g*N; -b[12]=a*J+e*C+f*S+g*d;b[1]=h*y+k*x+m*F+q*L;b[5]=h*I+k*B+m*H+q*M;b[9]=h*A+k*D+m*K+q*N;b[13]=h*J+k*C+m*S+q*d;b[2]=n*y+l*x+r*F+t*L;b[6]=n*I+l*B+r*H+t*M;b[10]=n*A+l*D+r*K+t*N;b[14]=n*J+l*C+r*S+t*d;b[3]=p*y+w*x+z*F+c*L;b[7]=p*I+w*B+z*H+c*M;b[11]=p*A+w*D+z*K+c*N;b[15]=p*J+w*C+z*S+c*d;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},applyToBufferAttribute:function(){var a= -new p;return function(b){for(var c=0,d=b.count;cthis.determinant()&&(g=-g);c.x=f[12];c.y=f[13];c.z=f[14];b.copy(this);c=1/g;var f=1/h,m=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]*=m;b.elements[9]*=m;b.elements[10]*=m;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makePerspective:function(a,b,c,d,e,f){void 0===f&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.");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/(c-d);g[9]=(c+d)/(c-d);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}, -makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=1/(b-a),k=1/(c-d),m=1/(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*m;g[14]=-((f+e)*m);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},equals:function(a){var b=this.elements;a=a.elements;for(var c=0;16>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;16>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]); -void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a}});Object.assign(ha,{slerp:function(a,b,c,d){return c.copy(a).slerp(b,d)},slerpFlat:function(a,b,c,d,e,f,g){var h=c[d+0],k=c[d+1],m=c[d+2];c=c[d+3];d=e[f+0];var q=e[f+1],l=e[f+2];e=e[f+3];if(c!==e||h!==d||k!==q||m!==l){f=1-g;var u=h*d+k*q+m*l+c*e,r=0<= -u?1:-1,p=1-u*u;p>Number.EPSILON&&(p=Math.sqrt(p),u=Math.atan2(p,u*r),f=Math.sin(f*u)/p,g=Math.sin(g*u)/p);r*=g;h=h*f+d*r;k=k*f+q*r;m=m*f+l*r;c=c*f+e*r;f===1-g&&(g=1/Math.sqrt(h*h+k*k+m*m+c*c),h*=g,k*=g,m*=g,c*=g)}a[b]=h;a[b+1]=k;a[b+2]=m;a[b+3]=c}});Object.defineProperties(ha.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this.onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this.onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z= -a;this.onChangeCallback()}},w:{get:function(){return this._w},set:function(a){this._w=a;this.onChangeCallback()}}});Object.assign(ha.prototype,{set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z;this._w=a.w;this.onChangeCallback();return this},setFromEuler:function(a,b){if(!a||!a.isEuler)throw Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order."); -var c=a._x,d=a._y,e=a._z;a=a.order;var f=Math.cos,g=Math.sin,h=f(c/2),k=f(d/2),f=f(e/2),c=g(c/2),d=g(d/2),e=g(e/2);"XYZ"===a?(this._x=c*k*f+h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f-c*d*e):"YXZ"===a?(this._x=c*k*f+h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f+c*d*e):"ZXY"===a?(this._x=c*k*f-h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f-c*d*e):"ZYX"===a?(this._x=c*k*f-h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f+c*d*e):"YZX"===a?(this._x= -c*k*f+h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f-c*d*e):"XZY"===a&&(this._x=c*k*f-h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f+c*d*e);if(!1!==b)this.onChangeCallback();return this},setFromAxisAngle:function(a,b){b/=2;var c=Math.sin(b);this._x=a.x*c;this._y=a.y*c;this._z=a.z*c;this._w=Math.cos(b);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],m=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=new p,b;return function(c,d){void 0===a&&(a=new p);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;return this.normalize()}}(),inverse:function(){return this.conjugate().normalize()},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)},premultiply:function(a){return this.multiplyQuaternions(a, -this)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z;a=a._w;var f=b._x,g=b._y,h=b._z;b=b._w;this._x=c*b+a*f+d*h-e*g;this._y=d*b+a*g+e*f-c*h;this._z=e*b+a*h+c*g-d*f;this._w=a*b-c*f-d*g-e*h;this.onChangeCallback();return 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;a=Math.sqrt(1-g*g);if(.001>Math.abs(a))return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;var h=Math.atan2(a,g),g=Math.sin((1-b)*h)/a;b=Math.sin(b*h)/a;this._w=f*g+this._w*b;this._x=c*g+this._x*b;this._y=d*g+this._y*b;this._z=e*g+this._z*b;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(){}});Object.assign(p.prototype,{isVector3:!0,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setScalar:function(a){this.z=this.y=this.x=a;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);}return this},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);}},clone:function(){return new this.constructor(this.x,this.y,this.z)},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},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;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},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 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=new ha;return function(b){b&&b.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.");return this.applyQuaternion(a.setFromEuler(b))}}(),applyAxisAngle:function(){var a=new ha;return function(b,c){return this.applyQuaternion(a.setFromAxisAngle(b,c))}}(),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;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,m=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b* --e+k*-g-m*-f;this.y=k*a+b*-f+m*-e-h*-g;this.z=m*a+b*-g+h*-f-k*-e;return this},project:function(){var a=new H;return function(b){a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyMatrix4(a)}}(),unproject:function(){var a=new H;return function(b){a.multiplyMatrices(b.matrixWorld,a.getInverse(b.projectionMatrix));return this.applyMatrix4(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;return this.normalize()},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y, -this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));return this},clampScalar:function(){var a=new p,b=new p;return function(c,d){a.set(c,c,c);b.set(d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},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)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},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){return this.subVectors(b,a).multiplyScalar(c).add(a)},cross:function(a,b){return void 0!== -b?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b)):this.crossVectors(this,a)},crossVectors:function(a,b){var c=a.x,d=a.y;a=a.z;var e=b.x,f=b.y;b=b.z;this.x=d*b-a*f;this.y=a*e-c*b;this.z=c*f-d*e;return this},projectOnVector:function(a){var b=a.dot(this)/a.lengthSq();return this.copy(a).multiplyScalar(b)},projectOnPlane:function(){var a=new p;return function(b){a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a= -new p;return function(b){return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/Math.sqrt(this.lengthSq()*a.lengthSq());return Math.acos(O.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},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)+Math.abs(this.z-a.z)},setFromSpherical:function(a){var b=Math.sin(a.phi)* -a.radius;this.x=b*Math.sin(a.theta);this.y=Math.cos(a.phi)*a.radius;this.z=b*Math.cos(a.theta);return this},setFromCylindrical:function(a){this.x=a.radius*Math.sin(a.theta);this.y=a.y;this.z=a.radius*Math.cos(a.theta);return this},setFromMatrixPosition:function(a){a=a.elements;this.x=a[12];this.y=a[13];this.z=a[14];return this},setFromMatrixScale:function(a){var b=this.setFromMatrixColumn(a,0).length(),c=this.setFromMatrixColumn(a,1).length();a=this.setFromMatrixColumn(a,2).length();this.x=b;this.y= -c;this.z=a;return this},setFromMatrixColumn:function(a,b){return this.fromArray(a.elements,4*b)},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},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."); -this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);return this}});Object.assign(ta.prototype,{isMatrix3:!0,set:function(a,b,c,d,e,f,g,h,k){var m=this.elements;m[0]=a;m[1]=d;m[2]=g;m[3]=b;m[4]=e;m[5]=h;m[6]=c;m[7]=f;m[8]=k;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]= -a[8];return this},setFromMatrix4:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[1],a[5],a[9],a[2],a[6],a[10]);return this},applyToBufferAttribute:function(){var a=new p;return function(b){for(var c=0,d=b.count;cc;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;9>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8]; -return a}});var zf=0;V.DEFAULT_IMAGE=void 0;V.DEFAULT_MAPPING=300;V.prototype=Object.assign(Object.create(xa.prototype),{constructor:V,isTexture:!0,clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.name=a.name;this.image=a.image;this.mipmaps=a.mipmaps.slice(0);this.mapping=a.mapping;this.wrapS=a.wrapS;this.wrapT=a.wrapT;this.magFilter=a.magFilter;this.minFilter=a.minFilter;this.anisotropy=a.anisotropy;this.format=a.format;this.type=a.type;this.offset.copy(a.offset);this.repeat.copy(a.repeat); -this.center.copy(a.center);this.rotation=a.rotation;this.matrixAutoUpdate=a.matrixAutoUpdate;this.matrix.copy(a.matrix);this.generateMipmaps=a.generateMipmaps;this.premultiplyAlpha=a.premultiplyAlpha;this.flipY=a.flipY;this.unpackAlignment=a.unpackAlignment;this.encoding=a.encoding;return this},toJSON:function(a){var b=void 0===a||"string"===typeof a;if(!b&&void 0!==a.textures[this.uuid])return a.textures[this.uuid];var c={metadata:{version:4.5,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid, -name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY};if(void 0!==this.image){var d=this.image;void 0===d.uuid&&(d.uuid=O.generateUUID());if(!b&&void 0===a.images[d.uuid]){var e=a.images,f=d.uuid,g=d.uuid;if(d instanceof HTMLCanvasElement)var h=d;else{h=document.createElementNS("http://www.w3.org/1999/xhtml", -"canvas");h.width=d.width;h.height=d.height;var k=h.getContext("2d");d instanceof ImageData?k.putImageData(d,0,0):k.drawImage(d,0,0,d.width,d.height)}h=2048a.x||1a.x?0:1;break;case 1002:a.x=1===Math.abs(Math.floor(a.x)%2)?Math.ceil(a.x)-a.x:a.x-Math.floor(a.x)}if(0>a.y||1a.y?0:1;break;case 1002:a.y=1===Math.abs(Math.floor(a.y)%2)?Math.ceil(a.y)-a.y:a.y-Math.floor(a.y)}this.flipY&&(a.y=1-a.y)}}});Object.defineProperty(V.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.assign(aa.prototype,{isVector4:!0,set:function(a,b,c,d){this.x=a;this.y= -b;this.z=c;this.w=d;return this},setScalar:function(a){this.w=this.z=this.y=this.x=a;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);}return this},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);}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},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},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;this.w+=a.w*b;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},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){return this.multiplyScalar(1/ -a)},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){a=a.elements;var b=a[0];var c=a[4];var d=a[8],e=a[1],f=a[5],g=a[9];var h=a[2];var k=a[6];var m=a[10];if(.01>Math.abs(c-e)&&.01>Math.abs(d-h)&&.01>Math.abs(g-k)){if(.1>Math.abs(c+e)&&.1>Math.abs(d+h)&&.1>Math.abs(g+k)&&.1>Math.abs(b+f+m-3))return this.set(1,0,0,0),this;a=Math.PI; -b=(b+1)/2;f=(f+1)/2;m=(m+1)/2;c=(c+e)/4;d=(d+h)/4;g=(g+k)/4;b>f&&b>m?.01>b?(k=0,c=h=.707106781):(k=Math.sqrt(b),h=c/k,c=d/k):f>m?.01>f?(k=.707106781,h=0,c=.707106781):(h=Math.sqrt(f),k=c/h,c=g/h):.01>m?(h=k=.707106781,c=0):(c=Math.sqrt(m),k=d/c,h=g/c);this.set(k,h,c,a);return this}a=Math.sqrt((k-g)*(k-g)+(d-h)*(d-h)+(e-c)*(e-c));.001>Math.abs(a)&&(a=1);this.x=(k-g)/a;this.y=(d-h)/a;this.z=(e-c)/a;this.w=Math.acos((b+f+m-1)/2);return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y, -a.y);this.z=Math.min(this.z,a.z);this.w=Math.min(this.w,a.w);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);this.w=Math.max(this.w,a.w);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));this.w=Math.max(a.w,Math.min(b.w,this.w));return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new aa,b=new aa);a.set(c, -c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},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)},manhattanLength: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()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},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){return this.subVectors(b,a).multiplyScalar(c).add(a)},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},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute()."); -this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);this.w=a.getW(b);return this}});gb.prototype=Object.assign(Object.create(xa.prototype),{constructor:gb,isWebGLRenderTarget:!0,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.dispose();this.viewport.set(0,0,a,b);this.scissor.set(0,0,a,b)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.width=a.width;this.height=a.height;this.viewport.copy(a.viewport);this.texture=a.texture.clone(); -this.depthBuffer=a.depthBuffer;this.stencilBuffer=a.stencilBuffer;this.depthTexture=a.depthTexture;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});Hb.prototype=Object.create(gb.prototype);Hb.prototype.constructor=Hb;Hb.prototype.isWebGLRenderTargetCube=!0;hb.prototype=Object.create(V.prototype);hb.prototype.constructor=hb;hb.prototype.isDataTexture=!0;Wa.prototype=Object.create(V.prototype);Wa.prototype.constructor=Wa;Wa.prototype.isCubeTexture=!0;Object.defineProperty(Wa.prototype, -"images",{get:function(){return this.image},set:function(a){this.image=a}});var Ne=new V,Oe=new Wa,Ie=[],Ke=[],Me=new Float32Array(16),Le=new Float32Array(9);Se.prototype.setValue=function(a,b){for(var c=this.seq,d=0,e=c.length;d!==e;++d){var f=c[d];f.setValue(a,b[f.id])}};var Vd=/([\w\d_]+)(\])?(\[|\.)?/g;ib.prototype.setValue=function(a,b,c){b=this.map[b];void 0!==b&&b.setValue(a,c,this.renderer)};ib.prototype.setOptional=function(a,b,c){b=b[c];void 0!==b&&this.setValue(a,c,b)};ib.upload=function(a, -b,c,d){for(var e=0,f=b.length;e!==f;++e){var g=b[e],h=c[g.id];!1!==h.needsUpdate&&g.setValue(a,h.value,d)}};ib.seqWithValue=function(a,b){for(var c=[],d=0,e=a.length;d!==e;++d){var f=a[d];f.id in b&&c.push(f)}return c};var Jg={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272, -cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265, -dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323, -lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912, -mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864, -seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};Object.assign(F.prototype,{isColor:!0,r:1,g:1,b:1,set:function(a){a&&a.isColor?this.copy(a):"number"===typeof a?this.setHex(a):"string"=== -typeof a&&this.setStyle(a);return this},setScalar:function(a){this.b=this.g=this.r=a;return this},setHex:function(a){a=Math.floor(a);this.r=(a>>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(){function a(a,c,d){0>d&&(d+=1);1d?c:d<2/3?a+6*(c-a)*(2/3-d):a}return function(b,c,d){b=O.euclideanModulo(b,1);c=O.clamp(c,0,1);d=O.clamp(d,0,1);0===c?this.r=this.g=this.b=d:(c= -.5>=d?d*(1+c):d+c-d*c,d=2*d-c,this.r=a(d,c,b+1/3),this.g=a(d,c,b),this.b=a(d,c,b-1/3));return this}}(),setStyle:function(a){function b(b){void 0!==b&&1>parseFloat(b)&&console.warn("THREE.Color: Alpha component of "+a+" will be ignored.")}var c;if(c=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(a)){var d=c[2];switch(c[1]){case "rgb":case "rgba":if(c=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(255,parseInt(c[1],10))/255,this.g=Math.min(255,parseInt(c[2],10))/ -255,this.b=Math.min(255,parseInt(c[3],10))/255,b(c[5]),this;if(c=/^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(100,parseInt(c[1],10))/100,this.g=Math.min(100,parseInt(c[2],10))/100,this.b=Math.min(100,parseInt(c[3],10))/100,b(c[5]),this;break;case "hsl":case "hsla":if(c=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d)){var d=parseFloat(c[1])/360,e=parseInt(c[2],10)/100,f=parseInt(c[3],10)/100;b(c[5]);return this.setHSL(d, -e,f)}}}else if(c=/^\#([A-Fa-f0-9]+)$/.exec(a)){c=c[1];d=c.length;if(3===d)return this.r=parseInt(c.charAt(0)+c.charAt(0),16)/255,this.g=parseInt(c.charAt(1)+c.charAt(1),16)/255,this.b=parseInt(c.charAt(2)+c.charAt(2),16)/255,this;if(6===d)return this.r=parseInt(c.charAt(0)+c.charAt(1),16)/255,this.g=parseInt(c.charAt(2)+c.charAt(3),16)/255,this.b=parseInt(c.charAt(4)+c.charAt(5),16)/255,this}a&&0=h?k/(e+f):k/(2-e-f);switch(e){case b:g=(c-d)/k+(c 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.86267 + (0.49788 + 0.01436 * y ) * y;\n\tfloat b = 3.45068 + (4.18814 + y) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\n\treturn result;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n", +e);this.setIndex(f);this.addAttribute("position",new B(g,3));this.addAttribute("normal",new B(h,3));this.addAttribute("uv",new B(k,2))}function bf(a,b,c,d,e){for(var f,g=0,h=b,k=c-d;h=b;e-=d)f=cf(e,a[e],a[e+1],f);f&&vb(f,f.next)&&(Qc(f),f=f.next);return f}function Rc(a,b){if(!a)return a;b||(b=a);do{var c=!1;if(a.steiner||!vb(a,a.next)&&0!==ta(a.prev,a,a.next))a=a.next;else{Qc(a);a=b=a.prev; +if(a===a.next)break;c=!0}}while(c||a!==b);return b}function Sc(a,b,c,d,e,f,g){if(a){if(!g&&f){var h=a,k=h;do null===k.z&&(k.z=fe(k.x,k.y,d,e,f)),k.prevZ=k.prev,k=k.nextZ=k.next;while(k!==h);k.prevZ.nextZ=null;k.prevZ=null;var h=k,m,q,n,l,r=1;do{k=h;var t=h=null;for(q=0;k;){q++;var p=k;for(m=n=0;mn.x?q.x>r.x?q.x:r.x:n.x>r.x?n.x:r.x,I=q.y>n.y?q.y>r.y?q.y:r.y:n.y>r.y?n.y:r.y;m=fe(q.x=m;){if(w!==t.prev&&w!==t.next&&zd(q.x,q.y,n.x,n.y,r.x, +r.y,w.x,w.y)&&0<=ta(w.prev,w,w.next)){t=!1;break a}w=w.prevZ}t=!0}}else a:if(t=a,q=t.prev,n=t,r=t.next,0<=ta(q,n,r))t=!1;else{for(m=t.next.next;m!==t.prev;){if(zd(q.x,q.y,n.x,n.y,r.x,r.y,m.x,m.y)&&0<=ta(m.prev,m,m.next)){t=!1;break a}m=m.next}t=!0}if(t)b.push(k.i/c),b.push(a.i/c),b.push(p.i/c),Qc(a),h=a=p.next;else if(a=p,a===h){if(!g)Sc(Rc(a),b,c,d,e,f,1);else if(1===g){g=b;h=c;k=a;do p=k.prev,t=k.next.next,!vb(p,t)&&df(p,k,k.next,t)&&Tc(p,t)&&Tc(t,p)&&(g.push(p.i/h),g.push(k.i/h),g.push(t.i/h), +Qc(k),Qc(k.next),k=a=t),k=k.next;while(k!==a);a=k;Sc(a,b,c,d,e,f,2)}else if(2===g)a:{g=a;do{for(h=g.next.next;h!==g.prev;){if(k=g.i!==h.i){k=g;p=h;if(t=k.next.i!==p.i&&k.prev.i!==p.i){b:{t=k;do{if(t.i!==k.i&&t.next.i!==k.i&&t.i!==p.i&&t.next.i!==p.i&&df(t,t.next,k,p)){t=!0;break b}t=t.next}while(t!==k);t=!1}t=!t}if(t=t&&Tc(k,p)&&Tc(p,k)){t=k;q=!1;n=(k.x+p.x)/2;p=(k.y+p.y)/2;do t.y>p!==t.next.y>p&&t.next.y!==t.y&&n<(t.next.x-t.x)*(p-t.y)/(t.next.y-t.y)+t.x&&(q=!q),t=t.next;while(t!==k);t=q}k=t}if(k){a= +ef(g,h);g=Rc(g,g.next);a=Rc(a,a.next);Sc(g,b,c,d,e,f);Sc(a,b,c,d,e,f);break a}h=h.next}g=g.next}while(g!==a)}break}}}}function Hg(a,b){return a.x-b.x}function Ig(a,b){var c=b,d=a.x,e=a.y,f=-Infinity;do{if(e<=c.y&&e>=c.next.y&&c.next.y!==c.y){var g=c.x+(e-c.y)*(c.next.x-c.x)/(c.next.y-c.y);if(g<=d&&g>f){f=g;if(g===d){if(e===c.y)return c;if(e===c.next.y)return c.next}var h=c.x=c.x&&c.x>=g&&d!==c.x&&zd(eh.x)&&Tc(c,a)&&(h=c,m=q)),c=c.next;return h}function fe(a,b,c,d,e){a=32767*(a-c)*e;b=32767*(b-d)*e;a=(a|a<<8)&16711935;a=(a|a<<4)&252645135;a=(a|a<<2)&858993459;b=(b|b<<8)&16711935;b=(b|b<<4)&252645135;b=(b|b<<2)&858993459;return(a|a<<1)&1431655765|((b|b<<1)&1431655765)<<1}function Jg(a){var b=a,c=a;do b.xta(a.prev,a,a.next)?0<=ta(a,b,a.next)&&0<=ta(a,a.prev,b):0>ta(a,b,a.prev)||0>ta(a,a.next,b)}function ef(a,b){var c=new ge(a.i,a.x,a.y),d=new ge(b.i,b.x,b.y),e=a.next,f=b.prev; +a.next=b;b.prev=a;c.next=e;e.prev=c;d.next=c;c.prev=d;f.next=d;d.prev=f;return d}function cf(a,b,c,d){a=new ge(a,b,c);d?(a.next=d.next,a.prev=d,d.next.prev=a,d.next=a):(a.prev=a,a.next=a);return a}function Qc(a){a.next.prev=a.prev;a.prev.next=a.next;a.prevZ&&(a.prevZ.nextZ=a.nextZ);a.nextZ&&(a.nextZ.prevZ=a.prevZ)}function ge(a,b,c){this.i=a;this.x=b;this.y=c;this.nextZ=this.prevZ=this.z=this.next=this.prev=null;this.steiner=!1}function ib(a,b){L.call(this);this.type="ExtrudeGeometry";this.parameters= +{shapes:a,options:b};this.fromBufferGeometry(new La(a,b));this.mergeVertices()}function La(a,b){"undefined"!==typeof a&&(E.call(this),this.type="ExtrudeBufferGeometry",a=Array.isArray(a)?a:[a],this.addShapeList(a,b),this.computeVertexNormals())}function Uc(a,b){L.call(this);this.type="TextGeometry";this.parameters={text:a,parameters:b};this.fromBufferGeometry(new ac(a,b));this.mergeVertices()}function ac(a,b){b=b||{};var c=b.font;if(!c||!c.isFont)return console.error("THREE.TextGeometry: font parameter is not an instance of THREE.Font."), +new L;a=c.generateShapes(a,b.size,b.curveSegments);b.amount=void 0!==b.height?b.height:50;void 0===b.bevelThickness&&(b.bevelThickness=10);void 0===b.bevelSize&&(b.bevelSize=8);void 0===b.bevelEnabled&&(b.bevelEnabled=!1);La.call(this,a,b);this.type="TextBufferGeometry"}function Vc(a,b,c,d,e,f,g){L.call(this);this.type="SphereGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};this.fromBufferGeometry(new wb(a,b,c,d,e,f,g));this.mergeVertices()} +function wb(a,b,c,d,e,f,g){E.call(this);this.type="SphereBufferGeometry";this.parameters={radius:a,widthSegments:b,heightSegments:c,phiStart:d,phiLength:e,thetaStart:f,thetaLength:g};a=a||1;b=Math.max(3,Math.floor(b)||8);c=Math.max(2,Math.floor(c)||6);d=void 0!==d?d:0;e=void 0!==e?e:2*Math.PI;f=void 0!==f?f:0;g=void 0!==g?g:Math.PI;var h=f+g,k,m,q=0,n=[],l=new p,r=new p,t=[],v=[],w=[],z=[];for(m=0;m<=c;m++){var y=[],I=m/c;for(k=0;k<=b;k++){var A=k/b;l.x=-a*Math.cos(d+A*e)*Math.sin(f+I*g);l.y=a*Math.cos(f+ +I*g);l.z=a*Math.sin(d+A*e)*Math.sin(f+I*g);v.push(l.x,l.y,l.z);r.set(l.x,l.y,l.z).normalize();w.push(r.x,r.y,r.z);z.push(A,1-I);y.push(q++)}n.push(y)}for(m=0;mq;q++){var n=m[f[q]];var l=m[f[(q+1)%3]];d[0]=Math.min(n,l);d[1]=Math.max(n,l);n=d[0]+","+d[1];void 0===e[n]?e[n]={index1:d[0],index2:d[1],face1:h,face2:void 0}:e[n].face2=h}for(n in e)if(d=e[n],void 0===d.face2||g[d.face1].normal.dot(g[d.face2].normal)<=b)f=a[d.index1],c.push(f.x,f.y,f.z),f=a[d.index2],c.push(f.x,f.y,f.z);this.addAttribute("position",new B(c,3))}function zb(a,b,c,d,e,f,g,h){L.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:a, +radiusBottom:b,height:c,radialSegments:d,heightSegments:e,openEnded:f,thetaStart:g,thetaLength:h};this.fromBufferGeometry(new ab(a,b,c,d,e,f,g,h));this.mergeVertices()}function ab(a,b,c,d,e,f,g,h){function k(c){var e,f=new D,k=new p,u=0,v=!0===c?a:b,y=!0===c?1:-1;var x=t;for(e=1;e<=d;e++)n.push(0,w*y,0),l.push(0,y,0),r.push(.5,.5),t++;var B=t;for(e=0;e<=d;e++){var C=e/d*h+g,E=Math.cos(C),C=Math.sin(C);k.x=v*C;k.y=w*y;k.z=v*E;n.push(k.x,k.y,k.z);l.push(0,y,0);f.x=.5*E+.5;f.y=.5*C*y+.5;r.push(f.x,f.y); +t++}for(e=0;ethis.duration&&this.resetDuration();this.optimize()}function Pd(a){this.manager=void 0!==a?a:xa;this.textures={}}function le(a){this.manager=void 0!==a?a:xa}function kc(){this.onLoadStart=function(){};this.onLoadProgress=function(){};this.onLoadComplete=function(){}}function me(a){"boolean"===typeof a&&(console.warn("THREE.JSONLoader: showStatus parameter has been removed from constructor."), +a=void 0);this.manager=void 0!==a?a:xa;this.withCredentials=!1}function jf(a){this.manager=void 0!==a?a:xa;this.texturePath=""}function ne(a){"undefined"===typeof createImageBitmap&&console.warn("THREE.ImageBitmapLoader: createImageBitmap() not supported.");"undefined"===typeof fetch&&console.warn("THREE.ImageBitmapLoader: fetch() not supported.");this.manager=void 0!==a?a:xa;this.options=void 0}function oe(){this.type="ShapePath";this.subPaths=[];this.currentPath=null}function pe(a){this.type="Font"; +this.data=a}function kf(a){this.manager=void 0!==a?a:xa}function qe(a){this.manager=void 0!==a?a:xa}function lf(){this.type="StereoCamera";this.aspect=1;this.eyeSep=.064;this.cameraL=new ba;this.cameraL.layers.enable(1);this.cameraL.matrixAutoUpdate=!1;this.cameraR=new ba;this.cameraR.layers.enable(2);this.cameraR.matrixAutoUpdate=!1}function fd(a,b,c){x.call(this);this.type="CubeCamera";var d=new ba(90,1,a,b);d.up.set(0,-1,0);d.lookAt(new p(1,0,0));this.add(d);var e=new ba(90,1,a,b);e.up.set(0,-1, +0);e.lookAt(new p(-1,0,0));this.add(e);var f=new ba(90,1,a,b);f.up.set(0,0,1);f.lookAt(new p(0,1,0));this.add(f);var g=new ba(90,1,a,b);g.up.set(0,0,-1);g.lookAt(new p(0,-1,0));this.add(g);var h=new ba(90,1,a,b);h.up.set(0,-1,0);h.lookAt(new p(0,0,1));this.add(h);var k=new ba(90,1,a,b);k.up.set(0,-1,0);k.lookAt(new p(0,0,-1));this.add(k);this.renderTarget=new Jb(c,c,{format:1022,magFilter:1006,minFilter:1006});this.renderTarget.texture.name="CubeCamera";this.update=function(a,b){null===this.parent&& +this.updateMatrixWorld();var c=this.renderTarget,m=c.texture.generateMipmaps;c.texture.generateMipmaps=!1;c.activeCubeFace=0;a.render(b,d,c);c.activeCubeFace=1;a.render(b,e,c);c.activeCubeFace=2;a.render(b,f,c);c.activeCubeFace=3;a.render(b,g,c);c.activeCubeFace=4;a.render(b,h,c);c.texture.generateMipmaps=m;c.activeCubeFace=5;a.render(b,k,c);a.setRenderTarget(null)};this.clear=function(a,b,c,d){for(var e=this.renderTarget,f=0;6>f;f++)e.activeCubeFace=f,a.setRenderTarget(e),a.clear(b,c,d);a.setRenderTarget(null)}} +function re(){x.call(this);this.type="AudioListener";this.context=se.getContext();this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.filter=null}function lc(a){x.call(this);this.type="Audio";this.context=a.context;this.gain=this.context.createGain();this.gain.connect(a.getInput());this.autoplay=!1;this.buffer=null;this.loop=!1;this.offset=this.startTime=0;this.playbackRate=1;this.isPlaying=!1;this.hasPlaybackControl=!0;this.sourceType="empty";this.filters=[]}function te(a){lc.call(this, +a);this.panner=this.context.createPanner();this.panner.connect(this.gain)}function ue(a,b){this.analyser=a.context.createAnalyser();this.analyser.fftSize=void 0!==b?b:2048;this.data=new Uint8Array(this.analyser.frequencyBinCount);a.getOutput().connect(this.analyser)}function ve(a,b,c){this.binding=a;this.valueSize=c;a=Float64Array;switch(b){case "quaternion":b=this._slerp;break;case "string":case "bool":a=Array;b=this._select;break;default:b=this._lerp}this.buffer=new a(4*c);this._mixBufferRegion= +b;this.referenceCount=this.useCount=this.cumulativeWeight=0}function mf(a,b,c){c=c||qa.parseTrackName(b);this._targetGroup=a;this._bindings=a.subscribe_(b,c)}function qa(a,b,c){this.path=b;this.parsedPath=c||qa.parseTrackName(b);this.node=qa.findNode(a,this.parsedPath.nodeName)||a;this.rootNode=a}function nf(){this.uuid=Q.generateUUID();this._objects=Array.prototype.slice.call(arguments);this.nCachedObjects_=0;var a={};this._indicesByUUID=a;for(var b=0,c=arguments.length;b!==c;++b)a[arguments[b].uuid]= +b;this._paths=[];this._parsedPaths=[];this._bindings=[];this._bindingsIndicesByPath={};var d=this;this.stats={objects:{get total(){return d._objects.length},get inUse(){return this.total-d.nCachedObjects_}},get bindingsPerObject(){return d._bindings.length}}}function of(a,b,c){this._mixer=a;this._clip=b;this._localRoot=c||null;a=b.tracks;b=a.length;c=Array(b);for(var d={endingStart:2400,endingEnd:2400},e=0;e!==b;++e){var f=a[e].createInterpolant(null);c[e]=f;f.settings=d}this._interpolantSettings= +d;this._interpolants=c;this._propertyBindings=Array(b);this._weightInterpolant=this._timeScaleInterpolant=this._byClipCacheIndex=this._cacheIndex=null;this.loop=2201;this._loopCount=-1;this._startTime=null;this.time=0;this._effectiveWeight=this.weight=this._effectiveTimeScale=this.timeScale=1;this.repetitions=Infinity;this.paused=!1;this.enabled=!0;this.clampWhenFinished=!1;this.zeroSlopeAtEnd=this.zeroSlopeAtStart=!0}function we(a){this._root=a;this._initMemoryManager();this.time=this._accuIndex= +0;this.timeScale=1}function Qd(a,b){"string"===typeof a&&(console.warn("THREE.Uniform: Type parameter is no longer needed."),a=b);this.value=a}function xe(){E.call(this);this.type="InstancedBufferGeometry";this.maxInstancedCount=void 0}function ye(a,b,c,d){this.uuid=Q.generateUUID();this.data=a;this.itemSize=b;this.offset=c;this.normalized=!0===d}function mc(a,b){this.uuid=Q.generateUUID();this.array=a;this.stride=b;this.count=void 0!==a?a.length/b:0;this.dynamic=!1;this.updateRange={offset:0,count:-1}; +this.onUploadCallback=function(){};this.version=0}function ze(a,b,c){mc.call(this,a,b);this.meshPerAttribute=c||1}function Ae(a,b,c){M.call(this,a,b);this.meshPerAttribute=c||1}function pf(a,b,c,d){this.ray=new sb(a,b);this.near=c||0;this.far=d||Infinity;this.params={Mesh:{},Line:{},LOD:{},Points:{threshold:1},Sprite:{}};Object.defineProperties(this.params,{PointCloud:{get:function(){console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points.");return this.Points}}})}function qf(a, +b){return a.distance-b.distance}function Be(a,b,c,d){if(!1!==a.visible&&(a.raycast(b,c),!0===d)){a=a.children;d=0;for(var e=a.length;dc;c++,d++){var e=c/32*Math.PI*2,f=d/32*Math.PI*2;b.push(Math.cos(e),Math.sin(e),1,Math.cos(f),Math.sin(f),1)}a.addAttribute("position",new B(b,3));b=new W({fog:!1});this.cone=new X(a,b);this.add(this.cone);this.update()}function uf(a){var b=[];a&&a.isBone&&b.push(a);for(var c=0;ca?-1:0b;b++)a[b]=(16>b?"0":"")+b.toString(16).toUpperCase();return function(){var b=4294967295*Math.random()|0,d=4294967295*Math.random()|0,e=4294967295*Math.random()|0,f=4294967295*Math.random()|0;return a[b&255]+a[b>>8&255]+a[b>>16&255]+a[b>>24&255]+"-"+a[d&255]+a[d>>8& +255]+"-"+a[d>>16&15|64]+a[d>>24&255]+"-"+a[e&63|128]+a[e>>8&255]+"-"+a[e>>16&255]+a[e>>24&255]+a[f&255]+a[f>>8&255]+a[f>>16&255]+a[f>>24&255]}}(),clamp:function(a,b,c){return Math.max(b,Math.min(c,a))},euclideanModulo:function(a,b){return(a%b+b)%b},mapLinear:function(a,b,c,d,e){return d+(a-b)*(e-d)/(c-b)},lerp:function(a,b,c){return(1-c)*a+c*b},smoothstep:function(a,b,c){if(a<=b)return 0;if(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)},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(a){return a*Q.DEG2RAD},radToDeg:function(a){return a*Q.RAD2DEG},isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},ceilPowerOfTwo:function(a){return Math.pow(2,Math.ceil(Math.log(a)/Math.LN2))},floorPowerOfTwo:function(a){return Math.pow(2,Math.floor(Math.log(a)/ +Math.LN2))}};Object.defineProperties(D.prototype,{width:{get:function(){return this.x},set:function(a){this.x=a}},height:{get:function(){return this.y},set:function(a){this.y=a}}});Object.assign(D.prototype,{isVector2:!0,set:function(a,b){this.x=a;this.y=b;return this},setScalar:function(a){this.y=this.x=a;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);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y)},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},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},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;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},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){return this.multiplyScalar(1/a)},applyMatrix3:function(a){var b=this.x,c=this.y;a=a.elements;this.x=a[0]*b+a[3]*c+a[6];this.y=a[1]*b+a[4]*c+a[7];return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);return this},clamp:function(a, +b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));return this},clampScalar:function(){var a=new D,b=new D;return function(c,d){a.set(c,c);b.set(d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},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)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length()|| +1)},angle:function(){var a=Math.atan2(this.y,this.x);0>a&&(a+=2*Math.PI);return a},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},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)},setLength:function(a){return this.normalize().multiplyScalar(a)},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){return this.subVectors(b, +a).multiplyScalar(c).add(a)},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},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);return this},rotateAround:function(a,b){var c=Math.cos(b);b=Math.sin(b);var d= +this.x-a.x,e=this.y-a.y;this.x=d*c-e*b+a.x;this.y=d*b+e*c+a.y;return this}});Object.assign(O.prototype,{isMatrix4:!0,set:function(a,b,c,d,e,f,g,h,k,m,q,l,u,r,t,p){var n=this.elements;n[0]=a;n[4]=b;n[8]=c;n[12]=d;n[1]=e;n[5]=f;n[9]=g;n[13]=h;n[2]=k;n[6]=m;n[10]=q;n[14]=l;n[3]=u;n[7]=r;n[11]=t;n[15]=p;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},clone:function(){return(new O).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements;b[0]= +a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return this},copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a,b,c){a.setFromMatrixColumn(this,0);b.setFromMatrixColumn(this,1);c.setFromMatrixColumn(this,2);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0, +1);return this},extractRotation:function(){var a=new p;return function(b){var c=this.elements,d=b.elements,e=1/a.setFromMatrixColumn(b,0).length(),f=1/a.setFromMatrixColumn(b,1).length();b=1/a.setFromMatrixColumn(b,2).length();c[0]=d[0]*e;c[1]=d[1]*e;c[2]=d[2]*e;c[4]=d[4]*f;c[5]=d[5]*f;c[6]=d[6]*f;c[8]=d[8]*b;c[9]=d[9]*b;c[10]=d[10]*b;return this}}(),makeRotationFromEuler:function(a){a&&a.isEuler||console.error("THREE.Matrix4: .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){var k=f*h;var m=f*e;var q=c*h;a=c*e;b[0]=g*h;b[4]=-g*e;b[8]=d;b[1]=m+q*d;b[5]=k-a*d;b[9]=-c*g;b[2]=a-k*d;b[6]=q+m*d;b[10]=f*g}else"YXZ"===a.order?(k=g*h,m=g*e,q=d*h,a=d*e,b[0]=k+a*c,b[4]=q*c-m,b[8]=f*d,b[1]=f*e,b[5]=f*h,b[9]=-c,b[2]=m*c-q,b[6]=a+k*c,b[10]=f*g):"ZXY"===a.order?(k=g*h,m=g*e,q=d*h,a=d*e,b[0]=k-a*c,b[4]=-f*e,b[8]=q+m*c,b[1]=m+q*c,b[5]=f*h,b[9]= +a-k*c,b[2]=-f*d,b[6]=c,b[10]=f*g):"ZYX"===a.order?(k=f*h,m=f*e,q=c*h,a=c*e,b[0]=g*h,b[4]=q*d-m,b[8]=k*d+a,b[1]=g*e,b[5]=a*d+k,b[9]=m*d-q,b[2]=-d,b[6]=c*g,b[10]=f*g):"YZX"===a.order?(k=f*g,m=f*d,q=c*g,a=c*d,b[0]=g*h,b[4]=a-k*e,b[8]=q*e+m,b[1]=e,b[5]=f*h,b[9]=-c*h,b[2]=-d*h,b[6]=m*e+q,b[10]=k-a*e):"XZY"===a.order&&(k=f*g,m=f*d,q=c*g,a=c*d,b[0]=g*h,b[4]=-e,b[8]=d*h,b[1]=k*e+a,b[5]=f*h,b[9]=m*e-q,b[2]=q*e-m,b[6]=c*h,b[10]=a*e+k);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},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 m=c*h,c=c*k,q=d*h,d=d*k,e=e*k,g=f*g,h=f*h,f=f*k;b[0]=1-(q+e);b[4]=m-f;b[8]=c+h;b[1]=m+f;b[5]=1-(a+e);b[9]=d-g;b[2]=c-h;b[6]=d+g;b[10]=1-(a+q);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 p,b=new p,c=new p;return function(d,e,f){var g=this.elements;c.subVectors(d,e);0===c.lengthSq()&&(c.z=1);c.normalize();a.crossVectors(f,c);0===a.lengthSq()&&(1===Math.abs(f.z)?c.x+=1E-4:c.z+=1E-4, +c.normalize(),a.crossVectors(f,c));a.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?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements; +b=this.elements;a=c[0];var e=c[4],f=c[8],g=c[12],h=c[1],k=c[5],m=c[9],q=c[13],n=c[2],l=c[6],r=c[10],t=c[14],p=c[3],w=c[7],z=c[11],c=c[15],y=d[0],I=d[4],A=d[8],J=d[12],x=d[1],B=d[5],D=d[9],C=d[13],E=d[2],H=d[6],K=d[10],S=d[14],L=d[3],N=d[7],M=d[11],d=d[15];b[0]=a*y+e*x+f*E+g*L;b[4]=a*I+e*B+f*H+g*N;b[8]=a*A+e*D+f*K+g*M;b[12]=a*J+e*C+f*S+g*d;b[1]=h*y+k*x+m*E+q*L;b[5]=h*I+k*B+m*H+q*N;b[9]=h*A+k*D+m*K+q*M;b[13]=h*J+k*C+m*S+q*d;b[2]=n*y+l*x+r*E+t*L;b[6]=n*I+l*B+r*H+t*N;b[10]=n*A+l*D+r*K+t*M;b[14]=n*J+l* +C+r*S+t*d;b[3]=p*y+w*x+z*E+c*L;b[7]=p*I+w*B+z*H+c*N;b[11]=p*A+w*D+z*K+c*M;b[15]=p*J+w*C+z*S+c*d;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},applyToBufferAttribute:function(){var a=new p;return function(b){for(var c=0,d=b.count;cthis.determinant()&&(g=-g);c.x=f[12];c.y=f[13];c.z=f[14];b.copy(this);c=1/g;var f=1/h,m=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]*=m;b.elements[9]*=m;b.elements[10]*=m;d.setFromRotationMatrix(b);e.x=g;e.y=h;e.z=k;return this}}(),makePerspective:function(a,b,c,d,e,f){void 0===f&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs."); +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/(c-d);g[9]=(c+d)/(c-d);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},makeOrthographic:function(a,b,c,d,e,f){var g=this.elements,h=1/(b-a),k=1/(c-d),m=1/(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*m;g[14]=-((f+e)*m);g[3]=0;g[7]=0;g[11]=0;g[15]=1;return this},equals:function(a){var b=this.elements; +a=a.elements;for(var c=0;16>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;16>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a}});Object.assign(ha,{slerp:function(a,b,c,d){return c.copy(a).slerp(b, +d)},slerpFlat:function(a,b,c,d,e,f,g){var h=c[d+0],k=c[d+1],m=c[d+2];c=c[d+3];d=e[f+0];var q=e[f+1],l=e[f+2];e=e[f+3];if(c!==e||h!==d||k!==q||m!==l){f=1-g;var u=h*d+k*q+m*l+c*e,r=0<=u?1:-1,p=1-u*u;p>Number.EPSILON&&(p=Math.sqrt(p),u=Math.atan2(p,u*r),f=Math.sin(f*u)/p,g=Math.sin(g*u)/p);r*=g;h=h*f+d*r;k=k*f+q*r;m=m*f+l*r;c=c*f+e*r;f===1-g&&(g=1/Math.sqrt(h*h+k*k+m*m+c*c),h*=g,k*=g,m*=g,c*=g)}a[b]=h;a[b+1]=k;a[b+2]=m;a[b+3]=c}});Object.defineProperties(ha.prototype,{x:{get:function(){return this._x}, +set:function(a){this._x=a;this.onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this.onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z=a;this.onChangeCallback()}},w:{get:function(){return this._w},set:function(a){this._w=a;this.onChangeCallback()}}});Object.assign(ha.prototype,{set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z, +this._w)},copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z;this._w=a.w;this.onChangeCallback();return this},setFromEuler:function(a,b){if(!a||!a.isEuler)throw Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");var c=a._x,d=a._y,e=a._z;a=a.order;var f=Math.cos,g=Math.sin,h=f(c/2),k=f(d/2),f=f(e/2),c=g(c/2),d=g(d/2),e=g(e/2);"XYZ"===a?(this._x=c*k*f+h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f-c*d*e):"YXZ"===a?(this._x=c*k*f+ +h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f+c*d*e):"ZXY"===a?(this._x=c*k*f-h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f-c*d*e):"ZYX"===a?(this._x=c*k*f-h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f+c*d*e):"YZX"===a?(this._x=c*k*f+h*d*e,this._y=h*d*f+c*k*e,this._z=h*k*e-c*d*f,this._w=h*k*f-c*d*e):"XZY"===a&&(this._x=c*k*f-h*d*e,this._y=h*d*f-c*k*e,this._z=h*k*e+c*d*f,this._w=h*k*f+c*d*e);if(!1!==b)this.onChangeCallback();return this},setFromAxisAngle:function(a, +b){b/=2;var c=Math.sin(b);this._x=a.x*c;this._y=a.y*c;this._z=a.z*c;this._w=Math.cos(b);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],m=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=new p,b;return function(c,d){void 0===a&&(a=new p);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;return this.normalize()}}(),inverse:function(){return this.conjugate().normalize()},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)},premultiply:function(a){return this.multiplyQuaternions(a,this)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,e=a._z;a=a._w;var f=b._x,g=b._y,h=b._z;b=b._w;this._x=c*b+a*f+d*h-e*g;this._y=d*b+a*g+e*f-c*h;this._z=e*b+a*h+c*g-d*f;this._w=a*b-c*f-d*g-e*h;this.onChangeCallback(); +return 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;a=Math.sqrt(1-g*g);if(.001>Math.abs(a))return this._w=.5*(f+this._w),this._x=.5*(c+this._x),this._y=.5*(d+this._y),this._z=.5*(e+this._z),this;var h=Math.atan2(a,g),g=Math.sin((1-b)*h)/a;b=Math.sin(b*h)/a; +this._w=f*g+this._w*b;this._x=c*g+this._x*b;this._y=d*g+this._y*b;this._z=e*g+this._z*b;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(){}});Object.assign(p.prototype,{isVector3:!0,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setScalar:function(a){this.z=this.y=this.x=a;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);}return this},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);}},clone:function(){return new this.constructor(this.x,this.y,this.z)},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},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;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},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 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=new ha;return function(b){b&&b.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order."); +return this.applyQuaternion(a.setFromEuler(b))}}(),applyAxisAngle:function(){var a=new ha;return function(b,c){return this.applyQuaternion(a.setFromAxisAngle(b,c))}}(),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;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,m=a*d+e*c-f*b,b=-e*b-f*c-g*d;this.x=h*a+b*-e+k*-g-m*-f;this.y=k*a+b*-f+m*-e-h*-g;this.z=m*a+b*-g+h*-f-k*-e;return this},project:function(){var a=new O;return function(b){a.multiplyMatrices(b.projectionMatrix,a.getInverse(b.matrixWorld));return this.applyMatrix4(a)}}(),unproject:function(){var a=new O;return function(b){a.multiplyMatrices(b.matrixWorld, +a.getInverse(b.projectionMatrix));return this.applyMatrix4(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;return this.normalize()},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);return this},max:function(a){this.x= +Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));return this},clampScalar:function(){var a=new p,b=new p;return function(c,d){a.set(c,c,c);b.set(d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},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)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},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){return this.subVectors(b,a).multiplyScalar(c).add(a)},cross:function(a,b){return void 0!==b?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b)):this.crossVectors(this,a)},crossVectors:function(a,b){var c=a.x,d=a.y;a=a.z;var e=b.x,f=b.y;b=b.z;this.x=d*b-a*f;this.y=a*e-c*b;this.z=c*f-d*e;return this},projectOnVector:function(a){var b= +a.dot(this)/a.lengthSq();return this.copy(a).multiplyScalar(b)},projectOnPlane:function(){var a=new p;return function(b){a.copy(this).projectOnVector(b);return this.sub(a)}}(),reflect:function(){var a=new p;return function(b){return this.sub(a.copy(b).multiplyScalar(2*this.dot(b)))}}(),angleTo:function(a){a=this.dot(a)/Math.sqrt(this.lengthSq()*a.lengthSq());return Math.acos(Q.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},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)+Math.abs(this.z-a.z)},setFromSpherical:function(a){var b=Math.sin(a.phi)*a.radius;this.x=b*Math.sin(a.theta);this.y=Math.cos(a.phi)*a.radius;this.z=b*Math.cos(a.theta);return this},setFromCylindrical:function(a){this.x=a.radius*Math.sin(a.theta);this.y=a.y;this.z=a.radius*Math.cos(a.theta);return this},setFromMatrixPosition:function(a){a=a.elements;this.x=a[12];this.y= +a[13];this.z=a[14];return this},setFromMatrixScale:function(a){var b=this.setFromMatrixColumn(a,0).length(),c=this.setFromMatrixColumn(a,1).length();a=this.setFromMatrixColumn(a,2).length();this.x=b;this.y=c;this.z=a;return this},setFromMatrixColumn:function(a,b){return this.fromArray(a.elements,4*b)},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},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);return this}});Object.assign(ma.prototype,{isMatrix3:!0,set:function(a,b,c,d,e,f,g,h,k){var m=this.elements;m[0]=a;m[1]=d;m[2]=g;m[3]=b;m[4]=e;m[5]=h;m[6]=c;m[7]=f;m[8]=k;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},clone:function(){return(new this.constructor).fromArray(this.elements)}, +copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return this},setFromMatrix4:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[1],a[5],a[9],a[2],a[6],a[10]);return this},applyToBufferAttribute:function(){var a=new p;return function(b){for(var c=0,d=b.count;cc;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;9>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c= +this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a}});var Af=0;U.DEFAULT_IMAGE=void 0;U.DEFAULT_MAPPING=300;U.prototype=Object.assign(Object.create(za.prototype),{constructor:U,isTexture:!0,clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.name=a.name;this.image=a.image;this.mipmaps=a.mipmaps.slice(0);this.mapping=a.mapping;this.wrapS=a.wrapS;this.wrapT=a.wrapT;this.magFilter=a.magFilter;this.minFilter= +a.minFilter;this.anisotropy=a.anisotropy;this.format=a.format;this.type=a.type;this.offset.copy(a.offset);this.repeat.copy(a.repeat);this.center.copy(a.center);this.rotation=a.rotation;this.matrixAutoUpdate=a.matrixAutoUpdate;this.matrix.copy(a.matrix);this.generateMipmaps=a.generateMipmaps;this.premultiplyAlpha=a.premultiplyAlpha;this.flipY=a.flipY;this.unpackAlignment=a.unpackAlignment;this.encoding=a.encoding;return this},toJSON:function(a){var b=void 0===a||"string"===typeof a;if(!b&&void 0!== +a.textures[this.uuid])return a.textures[this.uuid];var c={metadata:{version:4.5,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY};if(void 0!==this.image){var d=this.image;void 0===d.uuid&&(d.uuid=Q.generateUUID()); +if(!b&&void 0===a.images[d.uuid]){var e=a.images,f=d.uuid,g=d.uuid;if(d instanceof HTMLCanvasElement)var h=d;else{h=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");h.width=d.width;h.height=d.height;var k=h.getContext("2d");d instanceof ImageData?k.putImageData(d,0,0):k.drawImage(d,0,0,d.width,d.height)}h=2048a.x||1a.x?0:1;break;case 1002:a.x=1===Math.abs(Math.floor(a.x)%2)?Math.ceil(a.x)-a.x:a.x-Math.floor(a.x)}if(0>a.y||1a.y?0:1;break;case 1002:a.y=1===Math.abs(Math.floor(a.y)%2)?Math.ceil(a.y)-a.y:a.y-Math.floor(a.y)}this.flipY&&(a.y=1-a.y)}}});Object.defineProperty(U.prototype, +"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.assign(aa.prototype,{isVector4:!0,set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setScalar:function(a){this.w=this.z=this.y=this.x=a;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);}return this},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);}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},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},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;this.w+=a.w*b;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},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){return this.multiplyScalar(1/a)},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){a=a.elements;var b=a[0];var c=a[4];var d=a[8],e=a[1],f=a[5],g=a[9];var h=a[2];var k=a[6];var m=a[10];if(.01>Math.abs(c-e)&&.01>Math.abs(d-h)&&.01>Math.abs(g-k)){if(.1>Math.abs(c+ +e)&&.1>Math.abs(d+h)&&.1>Math.abs(g+k)&&.1>Math.abs(b+f+m-3))return this.set(1,0,0,0),this;a=Math.PI;b=(b+1)/2;f=(f+1)/2;m=(m+1)/2;c=(c+e)/4;d=(d+h)/4;g=(g+k)/4;b>f&&b>m?.01>b?(k=0,c=h=.707106781):(k=Math.sqrt(b),h=c/k,c=d/k):f>m?.01>f?(k=.707106781,h=0,c=.707106781):(h=Math.sqrt(f),k=c/h,c=g/h):.01>m?(h=k=.707106781,c=0):(c=Math.sqrt(m),k=d/c,h=g/c);this.set(k,h,c,a);return this}a=Math.sqrt((k-g)*(k-g)+(d-h)*(d-h)+(e-c)*(e-c));.001>Math.abs(a)&&(a=1);this.x=(k-g)/a;this.y=(d-h)/a;this.z=(e-c)/a; +this.w=Math.acos((b+f+m-1)/2);return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z,a.z);this.w=Math.min(this.w,a.w);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);this.w=Math.max(this.w,a.w);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));this.w=Math.max(a.w,Math.min(b.w, +this.w));return this},clampScalar:function(){var a,b;return function(c,d){void 0===a&&(a=new aa,b=new aa);a.set(c,c,c,c);b.set(d,d,d,d);return this.clamp(a,b)}}(),clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},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)},manhattanLength: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()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},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){return this.subVectors(b,a).multiplyScalar(c).add(a)},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},fromBufferAttribute:function(a, +b,c){void 0!==c&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);this.w=a.getW(b);return this}});kb.prototype=Object.assign(Object.create(za.prototype),{constructor:kb,isWebGLRenderTarget:!0,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.dispose();this.viewport.set(0,0,a,b);this.scissor.set(0,0,a,b)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.width= +a.width;this.height=a.height;this.viewport.copy(a.viewport);this.texture=a.texture.clone();this.depthBuffer=a.depthBuffer;this.stencilBuffer=a.stencilBuffer;this.depthTexture=a.depthTexture;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});Jb.prototype=Object.create(kb.prototype);Jb.prototype.constructor=Jb;Jb.prototype.isWebGLRenderTargetCube=!0;lb.prototype=Object.create(U.prototype);lb.prototype.constructor=lb;lb.prototype.isDataTexture=!0;db.prototype=Object.create(U.prototype); +db.prototype.constructor=db;db.prototype.isCubeTexture=!0;Object.defineProperty(db.prototype,"images",{get:function(){return this.image},set:function(a){this.image=a}});var Ne=new U,Oe=new db,Ie=[],Ke=[],Me=new Float32Array(16),Le=new Float32Array(9);Se.prototype.setValue=function(a,b){for(var c=this.seq,d=0,e=c.length;d!==e;++d){var f=c[d];f.setValue(a,b[f.id])}};var Vd=/([\w\d_]+)(\])?(\[|\.)?/g;mb.prototype.setValue=function(a,b,c){b=this.map[b];void 0!==b&&b.setValue(a,c,this.renderer)};mb.prototype.setOptional= +function(a,b,c){b=b[c];void 0!==b&&this.setValue(a,c,b)};mb.upload=function(a,b,c,d){for(var e=0,f=b.length;e!==f;++e){var g=b[e],h=c[g.id];!1!==h.needsUpdate&&g.setValue(a,h.value,d)}};mb.seqWithValue=function(a,b){for(var c=[],d=0,e=a.length;d!==e;++d){var f=a[d];f.id in b&&c.push(f)}return c};var Kg={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231, +cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539, +deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536, +lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154, +mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519, +royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};Object.assign(H.prototype,{isColor:!0,r:1,g:1,b:1,set:function(a){a&& +a.isColor?this.copy(a):"number"===typeof a?this.setHex(a):"string"===typeof a&&this.setStyle(a);return this},setScalar:function(a){this.b=this.g=this.r=a;return this},setHex:function(a){a=Math.floor(a);this.r=(a>>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(){function a(a,c,d){0>d&&(d+=1);1d?c:d<2/3?a+6*(c-a)*(2/3-d):a}return function(b,c,d){b=Q.euclideanModulo(b, +1);c=Q.clamp(c,0,1);d=Q.clamp(d,0,1);0===c?this.r=this.g=this.b=d:(c=.5>=d?d*(1+c):d+c-d*c,d=2*d-c,this.r=a(d,c,b+1/3),this.g=a(d,c,b),this.b=a(d,c,b-1/3));return this}}(),setStyle:function(a){function b(b){void 0!==b&&1>parseFloat(b)&&console.warn("THREE.Color: Alpha component of "+a+" will be ignored.")}var c;if(c=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(a)){var d=c[2];switch(c[1]){case "rgb":case "rgba":if(c=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(255, +parseInt(c[1],10))/255,this.g=Math.min(255,parseInt(c[2],10))/255,this.b=Math.min(255,parseInt(c[3],10))/255,b(c[5]),this;if(c=/^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(100,parseInt(c[1],10))/100,this.g=Math.min(100,parseInt(c[2],10))/100,this.b=Math.min(100,parseInt(c[3],10))/100,b(c[5]),this;break;case "hsl":case "hsla":if(c=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d)){var d=parseFloat(c[1])/360, +e=parseInt(c[2],10)/100,f=parseInt(c[3],10)/100;b(c[5]);return this.setHSL(d,e,f)}}}else if(c=/^\#([A-Fa-f0-9]+)$/.exec(a)){c=c[1];d=c.length;if(3===d)return this.r=parseInt(c.charAt(0)+c.charAt(0),16)/255,this.g=parseInt(c.charAt(1)+c.charAt(1),16)/255,this.b=parseInt(c.charAt(2)+c.charAt(2),16)/255,this;if(6===d)return this.r=parseInt(c.charAt(0)+c.charAt(1),16)/255,this.g=parseInt(c.charAt(2)+c.charAt(3),16)/255,this.b=parseInt(c.charAt(4)+c.charAt(5),16)/255,this}a&&0=h?k/(e+f): +k/(2-e-f);switch(e){case b:g=(c-d)/k+(c 0.0 ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tfloat maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\treturn distanceFalloff * maxDistanceCutoffFactor;\n#else\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n#endif\n\t}\n\treturn 1.0;\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat theta = acos( dot( N, V ) );\n\tvec2 uv = vec2(\n\t\tsqrt( saturate( roughness ) ),\n\t\tsaturate( theta / ( 0.5 * PI ) ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.86267 + (0.49788 + 0.01436 * y ) * y;\n\tfloat b = 3.45068 + (4.18814 + y) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tvec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );\n\treturn result;\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n", bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n", clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; ++ i ) {\n\t\tvec4 plane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t\t\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; ++ i ) {\n\t\t\tvec4 plane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t\n\t#endif\n#endif\n", clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvarying vec3 vViewPosition;\n#endif\n",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n", @@ -448,15 +448,15 @@ normal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n", points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_SIZEATTENUATION\n\t\tgl_PointSize = size * ( scale / - mvPosition.z );\n\t#else\n\t\tgl_PointSize = size;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n", shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n}\n",shadow_vert:"#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"}, -pb={basic:{uniforms:Ga.merge([K.common,K.specularmap,K.envmap,K.aomap,K.lightmap,K.fog]),vertexShader:Q.meshbasic_vert,fragmentShader:Q.meshbasic_frag},lambert:{uniforms:Ga.merge([K.common,K.specularmap,K.envmap,K.aomap,K.lightmap,K.emissivemap,K.fog,K.lights,{emissive:{value:new F(0)}}]),vertexShader:Q.meshlambert_vert,fragmentShader:Q.meshlambert_frag},phong:{uniforms:Ga.merge([K.common,K.specularmap,K.envmap,K.aomap,K.lightmap,K.emissivemap,K.bumpmap,K.normalmap,K.displacementmap,K.gradientmap, -K.fog,K.lights,{emissive:{value:new F(0)},specular:{value:new F(1118481)},shininess:{value:30}}]),vertexShader:Q.meshphong_vert,fragmentShader:Q.meshphong_frag},standard:{uniforms:Ga.merge([K.common,K.envmap,K.aomap,K.lightmap,K.emissivemap,K.bumpmap,K.normalmap,K.displacementmap,K.roughnessmap,K.metalnessmap,K.fog,K.lights,{emissive:{value:new F(0)},roughness:{value:.5},metalness:{value:.5},envMapIntensity:{value:1}}]),vertexShader:Q.meshphysical_vert,fragmentShader:Q.meshphysical_frag},points:{uniforms:Ga.merge([K.points, -K.fog]),vertexShader:Q.points_vert,fragmentShader:Q.points_frag},dashed:{uniforms:Ga.merge([K.common,K.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:Q.linedashed_vert,fragmentShader:Q.linedashed_frag},depth:{uniforms:Ga.merge([K.common,K.displacementmap]),vertexShader:Q.depth_vert,fragmentShader:Q.depth_frag},normal:{uniforms:Ga.merge([K.common,K.bumpmap,K.normalmap,K.displacementmap,{opacity:{value:1}}]),vertexShader:Q.normal_vert,fragmentShader:Q.normal_frag},cube:{uniforms:{tCube:{value:null}, -tFlip:{value:-1},opacity:{value:1}},vertexShader:Q.cube_vert,fragmentShader:Q.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:Q.equirect_vert,fragmentShader:Q.equirect_frag},distanceRGBA:{uniforms:Ga.merge([K.common,K.displacementmap,{referencePosition:{value:new p},nearDistance:{value:1},farDistance:{value:1E3}}]),vertexShader:Q.distanceRGBA_vert,fragmentShader:Q.distanceRGBA_frag},shadow:{uniforms:Ga.merge([K.lights,K.fog,{color:{value:new F(0)},opacity:{value:1}}]),vertexShader:Q.shadow_vert, -fragmentShader:Q.shadow_frag}};pb.physical={uniforms:Ga.merge([pb.standard.uniforms,{clearCoat:{value:0},clearCoatRoughness:{value:0}}]),vertexShader:Q.meshphysical_vert,fragmentShader:Q.meshphysical_frag};Object.assign(od.prototype,{set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<= this.max.y},getParameter:function(a,b){return(b||new D).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){return(b||new D).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new D;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),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},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)}});sc.prototype=Object.create(V.prototype);sc.prototype.constructor=sc;var $f=0;N.prototype=Object.assign(Object.create(xa.prototype),{constructor:N,isMaterial:!0,onBeforeCompile:function(){},setValues:function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0=== +this.max.min(a.max);return this},union:function(a){this.min.min(a.min);this.max.max(a.max);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)}});tc.prototype=Object.create(U.prototype);tc.prototype.constructor=tc;var ag=0;P.prototype=Object.assign(Object.create(za.prototype),{constructor:P,isMaterial:!0,onBeforeCompile:function(){},setValues:function(a){if(void 0!==a)for(var b in a){var c=a[b];if(void 0=== c)console.warn("THREE.Material: '"+b+"' parameter is undefined.");else if("shading"===b)console.warn("THREE."+this.type+": .shading has been removed. Use the boolean .flatShading instead."),this.flatShading=1===c?!0:!1;else{var d=this[b];void 0===d?console.warn("THREE."+this.type+": '"+b+"' is not a property of this material."):d&&d.isColor?d.set(c):d&&d.isVector3&&c&&c.isVector3?d.copy(c):this[b]="overdraw"===b?Number(c):c}}},toJSON:function(a){function b(a){var b=[],c;for(c in a){var d=a[c];delete d.metadata; b.push(d)}return b}var c=void 0===a||"string"===typeof a;c&&(a={textures:{},images:{}});var d={metadata:{version:4.5,type:"Material",generator:"Material.toJSON"}};d.uuid=this.uuid;d.type=this.type;""!==this.name&&(d.name=this.name);this.color&&this.color.isColor&&(d.color=this.color.getHex());void 0!==this.roughness&&(d.roughness=this.roughness);void 0!==this.metalness&&(d.metalness=this.metalness);this.emissive&&this.emissive.isColor&&(d.emissive=this.emissive.getHex());1!==this.emissiveIntensity&& (d.emissiveIntensity=this.emissiveIntensity);this.specular&&this.specular.isColor&&(d.specular=this.specular.getHex());void 0!==this.shininess&&(d.shininess=this.shininess);void 0!==this.clearCoat&&(d.clearCoat=this.clearCoat);void 0!==this.clearCoatRoughness&&(d.clearCoatRoughness=this.clearCoatRoughness);this.map&&this.map.isTexture&&(d.map=this.map.toJSON(a).uuid);this.alphaMap&&this.alphaMap.isTexture&&(d.alphaMap=this.alphaMap.toJSON(a).uuid);this.lightMap&&this.lightMap.isTexture&&(d.lightMap= @@ -467,439 +467,449 @@ this.depthWrite;0!==this.rotation&&(d.rotation=this.rotation);1!==this.linewidth this.wireframeLinewidth);"round"!==this.wireframeLinecap&&(d.wireframeLinecap=this.wireframeLinecap);"round"!==this.wireframeLinejoin&&(d.wireframeLinejoin=this.wireframeLinejoin);!0===this.morphTargets&&(d.morphTargets=!0);!0===this.skinning&&(d.skinning=!0);!1===this.visible&&(d.visible=!1);"{}"!==JSON.stringify(this.userData)&&(d.userData=this.userData);c&&(c=b(a.textures),a=b(a.images),0e&&(e=m);q>f&&(f=q);l>g&&(g=l)}this.min.set(b,c,d);this.max.set(e, +a.length,b=Array(c),d=0;d!==c;++d)b[d]=a[d].clone();this.clippingPlanes=b;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});eb.prototype=Object.create(P.prototype);eb.prototype.constructor=eb;eb.prototype.isMeshDepthMaterial=!0;eb.prototype.copy=function(a){P.prototype.copy.call(this,a);this.depthPacking=a.depthPacking;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.map=a.map;this.alphaMap=a.alphaMap;this.displacementMap=a.displacementMap;this.displacementScale= +a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;return this};fb.prototype=Object.create(P.prototype);fb.prototype.constructor=fb;fb.prototype.isMeshDistanceMaterial=!0;fb.prototype.copy=function(a){P.prototype.copy.call(this,a);this.referencePosition.copy(a.referencePosition);this.nearDistance=a.nearDistance;this.farDistance=a.farDistance;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.map=a.map;this.alphaMap= +a.alphaMap;this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;return this};Object.assign(Xa.prototype,{isBox3:!0,set:function(a,b){this.min.copy(a);this.max.copy(b);return this},setFromArray:function(a){for(var b=Infinity,c=Infinity,d=Infinity,e=-Infinity,f=-Infinity,g=-Infinity,h=0,k=a.length;he&&(e=m);q>f&&(f=q);l>g&&(g=l)}this.min.set(b,c,d);this.max.set(e, f,g);return this},setFromBufferAttribute:function(a){for(var b=Infinity,c=Infinity,d=Infinity,e=-Infinity,f=-Infinity,g=-Infinity,h=0,k=a.count;he&&(e=m);q>f&&(f=q);l>g&&(g=l)}this.min.set(b,c,d);this.max.set(e,f,g);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<= a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<=this.max.z},getParameter:function(a,b){return(b||new p).set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},intersectsSphere:function(){var a=new p;return function(b){this.clampPoint(b.center, a);return a.distanceToSquared(b.center)<=b.radius*b.radius}}(),intersectsPlane:function(a){if(0=a.constant},clampPoint:function(a, -b){return(b||new p).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new p;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a=new p;return function(b){b=b||new Fa;this.getCenter(b.center);b.radius=.5*this.getSize(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);this.isEmpty()&&this.makeEmpty();return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a= +b){return(b||new p).copy(a).clamp(this.min,this.max)},distanceToPoint:function(){var a=new p;return function(b){return a.copy(b).clamp(this.min,this.max).sub(b).length()}}(),getBoundingSphere:function(){var a=new p;return function(b){b=b||new Ia;this.getCenter(b.center);b.radius=.5*this.getSize(a).length();return b}}(),intersect:function(a){this.min.max(a.min);this.max.min(a.max);this.isEmpty()&&this.makeEmpty();return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this},applyMatrix4:function(){var a= [new p,new p,new p,new p,new p,new p,new p,new p];return function(b){if(this.isEmpty())return this;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.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)}});Object.assign(Fa.prototype,{set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(){var a=new Qa;return function(b,c){var d=this.center;void 0!==c?d.copy(c):a.setFromPoints(b).getCenter(d);for(var e=c=0,f=b.length;e=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<= -b*b},intersectsBox:function(a){return a.intersectsSphere(this)},intersectsPlane:function(a){return Math.abs(a.distanceToPoint(this.center))<=this.radius},clampPoint:function(a,b){var c=this.center.distanceToSquared(a);b=b||new p;b.copy(a);c>this.radius*this.radius&&(b.sub(this.center).normalize(),b.multiplyScalar(this.radius).add(this.center));return b},getBoundingBox:function(a){a=a||new Qa;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}});Object.assign(Ca.prototype,{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= +b*b},intersectsBox:function(a){return a.intersectsSphere(this)},intersectsPlane:function(a){return Math.abs(a.distanceToPoint(this.center))<=this.radius},clampPoint:function(a,b){var c=this.center.distanceToSquared(a);b=b||new p;b.copy(a);c>this.radius*this.radius&&(b.sub(this.center).normalize(),b.multiplyScalar(this.radius).add(this.center));return b},getBoundingBox:function(a){a=a||new Xa;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}});Object.assign(Ea.prototype,{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 p,b=new p;return function(c,d,e){d=a.subVectors(e,d).cross(b.subVectors(c,d)).normalize();this.setFromNormalAndCoplanarPoint(d,c);return this}}(),clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+ this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)-a.radius},projectPoint:function(a,b){return(b||new p).copy(this.normal).multiplyScalar(-this.distanceToPoint(a)).add(a)},intersectLine:function(){var a=new p;return function(b,c){c=c||new p;var d=b.delta(a),e=this.normal.dot(d);if(0===e){if(0===this.distanceToPoint(b.start))return c.copy(b.start)}else if(e=-(b.start.dot(this.normal)+this.constant)/e,!(0>e||1b&&0a&&0b&&0a&&0c;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],m=c[7],q=c[8],l=c[9],p=c[10],r=c[11],t=c[12],v=c[13],w=c[14],c=c[15];b[0].setComponents(f-a,m-g,r-q,c-t).normalize();b[1].setComponents(f+a,m+g,r+q,c+t).normalize();b[2].setComponents(f+d,m+h,r+l,c+v).normalize();b[3].setComponents(f-d,m-h,r-l,c-v).normalize();b[4].setComponents(f-e,m-k,r-p,c-w).normalize();b[5].setComponents(f+e,m+k,r+p,c+w).normalize();return this},intersectsObject:function(){var a=new Fa;return function(b){var c= -b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere).applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSprite:function(){var a=new Fa;return function(b){a.center.set(0,0,0);a.radius=.7071067811865476;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}});Za.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" "); -Za.DefaultOrder="XYZ";Object.defineProperties(Za.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this.onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this.onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z=a;this.onChangeCallback()}},order:{get:function(){return this._order},set:function(a){this._order=a;this.onChangeCallback()}}});Object.assign(Za.prototype,{isEuler:!0,set:function(a,b,c,d){this._x=a;this._y=b;this._z= -c;this._order=d||this._order;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},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=O.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],h=e[1],k=e[5],m=e[9],l=e[2],n=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(-m,e),this._z= +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],m=c[7],q=c[8],l=c[9],p=c[10],r=c[11],t=c[12],v=c[13],w=c[14],c=c[15];b[0].setComponents(f-a,m-g,r-q,c-t).normalize();b[1].setComponents(f+a,m+g,r+q,c+t).normalize();b[2].setComponents(f+d,m+h,r+l,c+v).normalize();b[3].setComponents(f-d,m-h,r-l,c-v).normalize();b[4].setComponents(f-e,m-k,r-p,c-w).normalize();b[5].setComponents(f+e,m+k,r+p,c+w).normalize();return this},intersectsObject:function(){var a=new Ia;return function(b){var c= +b.geometry;null===c.boundingSphere&&c.computeBoundingSphere();a.copy(c.boundingSphere).applyMatrix4(b.matrixWorld);return this.intersectsSphere(a)}}(),intersectsSprite:function(){var a=new Ia;return function(b){a.center.set(0,0,0);a.radius=.7071067811865476;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}});gb.RotationOrders="XYZ YZX ZXY XZY YXZ ZYX".split(" "); +gb.DefaultOrder="XYZ";Object.defineProperties(gb.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this.onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this.onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z=a;this.onChangeCallback()}},order:{get:function(){return this._order},set:function(a){this._order=a;this.onChangeCallback()}}});Object.assign(gb.prototype,{isEuler:!0,set:function(a,b,c,d){this._x=a;this._y=b;this._z= +c;this._order=d||this._order;this.onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},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=Q.clamp,e=a.elements;a=e[0];var f=e[4],g=e[8],h=e[1],k=e[5],m=e[9],l=e[2],n=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(-m,e),this._z= Math.atan2(-f,a)):(this._x=Math.atan2(n,k),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(m,-1,1)),.99999>Math.abs(m)?(this._y=Math.atan2(g,e),this._z=Math.atan2(h,k)):(this._y=Math.atan2(-l,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(n,-1,1)),.99999>Math.abs(n)?(this._y=Math.atan2(-l,e),this._z=Math.atan2(-f,k)):(this._y=0,this._z=Math.atan2(h,a))):"ZYX"===b?(this._y=Math.asin(-d(l,-1,1)),.99999>Math.abs(l)?(this._x=Math.atan2(n,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(-m,k),this._y=Math.atan2(-l,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(n,k),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-m,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=new H;return function(b,c,d){a.makeRotationFromQuaternion(b); +b?(this._z=Math.asin(d(h,-1,1)),.99999>Math.abs(h)?(this._x=Math.atan2(-m,k),this._y=Math.atan2(-l,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(n,k),this._y=Math.atan2(g,a)):(this._x=Math.atan2(-m,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=new O;return function(b,c,d){a.makeRotationFromQuaternion(b); return this.setFromRotationMatrix(a,c,d)}}(),setFromVector3:function(a,b){return this.set(a.x,a.y,a.z,b||this._order)},reorder:function(){var a=new ha;return function(b){a.setFromEuler(this);return 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 p(this._x,this._y,this._z)},onChange:function(a){this.onChangeCallback=a;return this},onChangeCallback:function(){}});Object.assign(Wd.prototype,{set:function(a){this.mask=1<g;g++)if(d[g]===d[(g+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(d=a[f],this.faces.splice(d,1),c=0,e= -this.faceVertexUvs.length;ca?b.copy(this.origin):b.copy(this.direction).multiplyScalar(a).add(this.origin)},distanceToPoint:function(a){return Math.sqrt(this.distanceSqToPoint(a))},distanceSqToPoint:function(){var a=new p;return function(b){var c=a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceToSquared(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceToSquared(b)}}(),distanceSqToSegment:function(){var a= -new p,b=new p,c=new p;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),m=c.dot(this.direction),l=-c.dot(b),n=c.lengthSq(),p=Math.abs(1-k*k);if(0=-r?e<=r?(h=1/p,d*=h,e*=h,k=d*(d+k*e+2*m)+e*(k*d+e+2*l)+n):(e=h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):(e=-h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):e<=-r?(d=Math.max(0,-(-k*h+m)),e=0b)return null; -b=Math.sqrt(b-e);e=d-b;d+=b;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),intersectsSphere:function(a){return this.distanceToPoint(a.center)<=a.radius},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){a=this.distanceToPlane(a);return null===a?null:this.at(a,b)},intersectsPlane:function(a){var b=a.distanceToPoint(this.origin); -return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},intersectBox:function(a,b){var c=1/this.direction.x;var d=1/this.direction.y;var e=1/this.direction.z,f=this.origin;if(0<=c){var g=(a.min.x-f.x)*c;c*=a.max.x-f.x}else g=(a.max.x-f.x)*c,c*=a.min.x-f.x;if(0<=d){var h=(a.min.y-f.y)*d;d*=a.max.y-f.y}else h=(a.max.y-f.y)*d,d*=a.min.y-f.y;if(g>d||h>c)return null;if(h>g||g!==g)g=h;if(da||h>c)return null; -if(h>g||g!==g)g=h;if(ac?null:this.at(0<=g?g:c,b)},intersectsBox:function(){var a=new p;return function(b){return null!==this.intersectBox(b,a)}}(),intersectTriangle:function(){var a=new p,b=new p,c=new p,d=new p;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));if(0>g||e+g>f)return null;e=-h*a.dot(d);return 0>e?null:this.at(e/f,k)}}(),applyMatrix4:function(a){this.origin.applyMatrix4(a);this.direction.transformDirection(a);return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}});Object.assign(Lb.prototype,{set:function(a,b){this.start.copy(a);this.end.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.start.copy(a.start); -this.end.copy(a.end);return this},getCenter:function(a){return(a||new p).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){return(a||new p).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){b=b||new p;return this.delta(b).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new p,b=new p;return function(c,d){a.subVectors(c, -this.start);b.subVectors(this.end,this.start);c=b.dot(b);c=b.dot(a)/c;d&&(c=O.clamp(c,0,1));return c}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new p;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)}});Object.assign(Sa,{normal:function(){var a=new p;return function(b,c,d,e){e=e||new p; -e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0=b.x+b.y}}()});Object.assign(Sa.prototype,{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},clone:function(){return(new this.constructor).copy(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 p,b=new p;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 p).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return Sa.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new Ca).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return Sa.barycoordFromPoint(a,this.a,this.b,this.c,b)},containsPoint:function(a){return Sa.containsPoint(a,this.a,this.b,this.c)},closestPointToPoint:function(){var a= -new Ca,b=[new Lb,new Lb,new Lb],c=new p,d=new p;return function(e,f){f=f||new p;var g=Infinity;a.setFromCoplanarPoints(this.a,this.b,this.c);a.projectPoint(e,c);if(!0===this.containsPoint(c))f.copy(c);else for(b[0].set(this.a,this.b),b[1].set(this.b,this.c),b[2].set(this.c,this.a),e=0;ec.far?null:{distance:b,point:z.clone(),object:a}}function c(c,d,e,f,m,l,q,n){g.fromBufferAttribute(f,l);h.fromBufferAttribute(f,q);k.fromBufferAttribute(f,n);if(c=b(c,c.material,d,e,g,h,k,w))m&&(u.fromBufferAttribute(m, -l),r.fromBufferAttribute(m,q),t.fromBufferAttribute(m,n),c.uv=a(w,g,h,k,u,r,t)),c.face=new Ra(l,q,n,Sa.normal(g,h,k)),c.faceIndex=l;return c}var d=new H,e=new ob,f=new Fa,g=new p,h=new p,k=new p,m=new p,l=new p,n=new p,u=new D,r=new D,t=new D,v=new p,w=new p,z=new p;return function(q,p){var v=this.geometry,z=this.material,y=this.matrixWorld;if(void 0!==z&&(null===v.boundingSphere&&v.computeBoundingSphere(),f.copy(v.boundingSphere),f.applyMatrix4(y),!1!==q.ray.intersectsSphere(f)&&(d.getInverse(y), -e.copy(q.ray).applyMatrix4(d),null===v.boundingBox||!1!==e.intersectsBox(v.boundingBox)))){var x;if(v.isBufferGeometry){var z=v.index,B=v.attributes.position,y=v.attributes.uv,D;if(null!==z){var C=0;for(D=z.count;Cf||(f=d.ray.origin.distanceTo(a),fd.far||e.push({distance:f,point:a.clone(),face:null,object:this}))}}(),clone:function(){return(new this.constructor(this.material)).copy(this)}});Cc.prototype=Object.assign(Object.create(x.prototype),{constructor:Cc,copy:function(a){x.prototype.copy.call(this, -a,!1);a=a.levels;for(var b=0,c=a.length;b=d[e].distance)d[e-1].object.visible=!1,d[e].object.visible=!0;else break;for(;ef||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l),ud.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}));else for(g=0,v=r.length/3-1;gf||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l), -ud.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g.isGeometry)for(k=g.vertices,m=k.length,g=0;gf||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l),ud.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}}}(),clone:function(){return(new this.constructor(this.geometry, -this.material)).copy(this)}});X.prototype=Object.assign(Object.create(oa.prototype),{constructor:X,isLineSegments:!0});yd.prototype=Object.assign(Object.create(oa.prototype),{constructor:yd,isLineLoop:!0});Da.prototype=Object.create(N.prototype);Da.prototype.constructor=Da;Da.prototype.isPointsMaterial=!0;Da.prototype.copy=function(a){N.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.size=a.size;this.sizeAttenuation=a.sizeAttenuation;return this};Pb.prototype=Object.assign(Object.create(x.prototype), -{constructor:Pb,isPoints:!0,raycast:function(){var a=new H,b=new ob,c=new Fa;return function(d,e){function f(a,c){var f=b.distanceSqToPoint(a);if(fd.far||e.push({distance:h,distanceToRay:Math.sqrt(f),point:a.clone(),index:c,face:null,object:g})}}var g=this,h=this.geometry,k=this.matrixWorld,m=d.params.Points.threshold;null===h.boundingSphere&&h.computeBoundingSphere();c.copy(h.boundingSphere);c.applyMatrix4(k); -c.radius+=m;if(!1!==d.ray.intersectsSphere(c)){a.getInverse(k);b.copy(d.ray).applyMatrix4(a);var m=m/((this.scale.x+this.scale.y+this.scale.z)/3),l=m*m,m=new p;if(h.isBufferGeometry){var n=h.index,h=h.attributes.position.array;if(null!==n)for(var u=n.array,n=0,r=u.length;n=a.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}});Qb.prototype=Object.create(V.prototype);Qb.prototype.constructor=Qb;Qb.prototype.isCompressedTexture=!0;Fc.prototype=Object.create(V.prototype);Fc.prototype.constructor=Fc;Fc.prototype.isDepthTexture=!0;Rb.prototype=Object.create(C.prototype); -Rb.prototype.constructor=Rb;Gc.prototype=Object.create(L.prototype);Gc.prototype.constructor=Gc;Sb.prototype=Object.create(C.prototype);Sb.prototype.constructor=Sb;Hc.prototype=Object.create(L.prototype);Hc.prototype.constructor=Hc;sa.prototype=Object.create(C.prototype);sa.prototype.constructor=sa;Ic.prototype=Object.create(L.prototype);Ic.prototype.constructor=Ic;Tb.prototype=Object.create(sa.prototype);Tb.prototype.constructor=Tb;Jc.prototype=Object.create(L.prototype);Jc.prototype.constructor= -Jc;qb.prototype=Object.create(sa.prototype);qb.prototype.constructor=qb;Kc.prototype=Object.create(L.prototype);Kc.prototype.constructor=Kc;Ub.prototype=Object.create(sa.prototype);Ub.prototype.constructor=Ub;Lc.prototype=Object.create(L.prototype);Lc.prototype.constructor=Lc;Vb.prototype=Object.create(sa.prototype);Vb.prototype.constructor=Vb;Mc.prototype=Object.create(L.prototype);Mc.prototype.constructor=Mc;Wb.prototype=Object.create(C.prototype);Wb.prototype.constructor=Wb;Nc.prototype=Object.create(L.prototype); -Nc.prototype.constructor=Nc;Xb.prototype=Object.create(C.prototype);Xb.prototype.constructor=Xb;Oc.prototype=Object.create(L.prototype);Oc.prototype.constructor=Oc;Yb.prototype=Object.create(C.prototype);Yb.prototype.constructor=Yb;var Kg={triangulate:function(a,b,c){c=c||2;var d=b&&b.length,e=d?b[0]*c:a.length,f=bf(a,0,e,c,!0),g=[];if(!f)return g;var h;if(d){var k=c,d=[],m;var l=0;for(m=b.length;l80*c){var r=h=a[0];var t=d=a[1];for(k=c;kh&&(h=l),b>d&&(d=b);h=Math.max(h-r,d-t);h=0!==h?1/h:0}Rc(f,g,c,r,t,h);return g}},Ta={area:function(a){for(var b=a.length,c=0,d=b-1,e=0;eTa.area(a)},triangulateShape:function(a,b){function c(a){var b=a.length;2Number.EPSILON){var k=Math.sqrt(h),m=Math.sqrt(f*f+g*g),h=b.x-e/k;b=b.y+d/k;g=((c.x-g/m-h)*g-(c.y+f/m-b)*f)/(d*g-e*f);f=h+d*g-a.x;d=b+e*g-a.y;e=f*f+d*d;if(2>=e)return new D(f,d);e=Math.sqrt(e/2)}else a=!1,d>Number.EPSILON?f>Number.EPSILON&&(a=!0):d<-Number.EPSILON?f<-Number.EPSILON&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(f=-e,e=Math.sqrt(h)):(f= -d,d=e,e=Math.sqrt(h/2));return new D(f/e,d/e)}function e(a,b){for(G=a.length;0<=--G;){var c=G;var d=G-1;0>d&&(d=a.length-1);var e,f=x+2*w;for(e=0;eMath.abs(g-k)?[new D(a,1-c),new D(h,1-d),new D(m,1-e),new D(n,1-b)]:[new D(g,1-c),new D(k,1-d),new D(l,1-e),new D(p,1-b)]}};Tc.prototype=Object.create(L.prototype);Tc.prototype.constructor=Tc;Zb.prototype=Object.create(Ja.prototype);Zb.prototype.constructor=Zb;Uc.prototype=Object.create(L.prototype);Uc.prototype.constructor=Uc;sb.prototype= -Object.create(C.prototype);sb.prototype.constructor=sb;Vc.prototype=Object.create(L.prototype);Vc.prototype.constructor=Vc;$b.prototype=Object.create(C.prototype);$b.prototype.constructor=$b;Wc.prototype=Object.create(L.prototype);Wc.prototype.constructor=Wc;ac.prototype=Object.create(C.prototype);ac.prototype.constructor=ac;bc.prototype=Object.create(L.prototype);bc.prototype.constructor=bc;cc.prototype=Object.create(C.prototype);cc.prototype.constructor=cc;dc.prototype=Object.create(C.prototype); -dc.prototype.constructor=dc;tb.prototype=Object.create(L.prototype);tb.prototype.constructor=tb;Ua.prototype=Object.create(C.prototype);Ua.prototype.constructor=Ua;Xc.prototype=Object.create(tb.prototype);Xc.prototype.constructor=Xc;Yc.prototype=Object.create(Ua.prototype);Yc.prototype.constructor=Yc;Zc.prototype=Object.create(L.prototype);Zc.prototype.constructor=Zc;ec.prototype=Object.create(C.prototype);ec.prototype.constructor=ec;var Ea=Object.freeze({WireframeGeometry:Rb,ParametricGeometry:Gc, -ParametricBufferGeometry:Sb,TetrahedronGeometry:Ic,TetrahedronBufferGeometry:Tb,OctahedronGeometry:Jc,OctahedronBufferGeometry:qb,IcosahedronGeometry:Kc,IcosahedronBufferGeometry:Ub,DodecahedronGeometry:Lc,DodecahedronBufferGeometry:Vb,PolyhedronGeometry:Hc,PolyhedronBufferGeometry:sa,TubeGeometry:Mc,TubeBufferGeometry:Wb,TorusKnotGeometry:Nc,TorusKnotBufferGeometry:Xb,TorusGeometry:Oc,TorusBufferGeometry:Yb,TextGeometry:Tc,TextBufferGeometry:Zb,SphereGeometry:Uc,SphereBufferGeometry:sb,RingGeometry:Vc, -RingBufferGeometry:$b,PlaneGeometry:zc,PlaneBufferGeometry:nb,LatheGeometry:Wc,LatheBufferGeometry:ac,ShapeGeometry:bc,ShapeBufferGeometry:cc,ExtrudeGeometry:ab,ExtrudeBufferGeometry:Ja,EdgesGeometry:dc,ConeGeometry:Xc,ConeBufferGeometry:Yc,CylinderGeometry:tb,CylinderBufferGeometry:Ua,CircleGeometry:Zc,CircleBufferGeometry:ec,BoxGeometry:Kb,BoxBufferGeometry:mb});fc.prototype=Object.create(N.prototype);fc.prototype.constructor=fc;fc.prototype.isShadowMaterial=!0;gc.prototype=Object.create(pa.prototype); -gc.prototype.constructor=gc;gc.prototype.isRawShaderMaterial=!0;Oa.prototype=Object.create(N.prototype);Oa.prototype.constructor=Oa;Oa.prototype.isMeshStandardMaterial=!0;Oa.prototype.copy=function(a){N.prototype.copy.call(this,a);this.defines={STANDARD:""};this.color.copy(a.color);this.roughness=a.roughness;this.metalness=a.metalness;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive); -this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.roughnessMap=a.roughnessMap;this.metalnessMap=a.metalnessMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.envMapIntensity=a.envMapIntensity;this.refractionRatio=a.refractionRatio; -this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};ub.prototype=Object.create(Oa.prototype);ub.prototype.constructor=ub;ub.prototype.isMeshPhysicalMaterial=!0;ub.prototype.copy=function(a){Oa.prototype.copy.call(this,a);this.defines={PHYSICAL:""};this.reflectivity=a.reflectivity;this.clearCoat= -a.clearCoat;this.clearCoatRoughness=a.clearCoatRoughness;return this};Ka.prototype=Object.create(N.prototype);Ka.prototype.constructor=Ka;Ka.prototype.isMeshPhongMaterial=!0;Ka.prototype.copy=function(a){N.prototype.copy.call(this,a);this.color.copy(a.color);this.specular.copy(a.specular);this.shininess=a.shininess;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap= -a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth= -a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};vb.prototype=Object.create(Ka.prototype);vb.prototype.constructor=vb;vb.prototype.isMeshToonMaterial=!0;vb.prototype.copy=function(a){Ka.prototype.copy.call(this,a);this.gradientMap=a.gradientMap;return this};wb.prototype=Object.create(N.prototype);wb.prototype.constructor=wb;wb.prototype.isMeshNormalMaterial= -!0;wb.prototype.copy=function(a){N.prototype.copy.call(this,a);this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};xb.prototype=Object.create(N.prototype); -xb.prototype.constructor=xb;xb.prototype.isMeshLambertMaterial=!0;xb.prototype.copy=function(a){N.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity= -a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};yb.prototype=Object.create(W.prototype);yb.prototype.constructor=yb;yb.prototype.isLineDashedMaterial=!0;yb.prototype.copy=function(a){W.prototype.copy.call(this,a);this.scale=a.scale;this.dashSize= -a.dashSize;this.gapSize=a.gapSize;return this};var Lg=Object.freeze({ShadowMaterial:fc,SpriteMaterial:$a,RawShaderMaterial:gc,ShaderMaterial:pa,PointsMaterial:Da,MeshPhysicalMaterial:ub,MeshStandardMaterial:Oa,MeshPhongMaterial:Ka,MeshToonMaterial:vb,MeshNormalMaterial:wb,MeshLambertMaterial:xb,MeshDepthMaterial:Xa,MeshDistanceMaterial:Ya,MeshBasicMaterial:ya,LineDashedMaterial:yb,LineBasicMaterial:W,Material:N}),Gb={enabled:!1,files:{},add:function(a,b){!1!==this.enabled&&(this.files[a]=b)},get:function(a){if(!1!== -this.enabled)return this.files[a]},remove:function(a){delete this.files[a]},clear:function(){this.files={}}},ja=new he,Va={};Object.assign(La.prototype,{load:function(a,b,c,d){void 0===a&&(a="");void 0!==this.path&&(a=this.path+a);a=this.manager.resolveURL(a);var e=this,f=Gb.get(a);if(void 0!==f)return e.manager.itemStart(a),setTimeout(function(){b&&b(f);e.manager.itemEnd(a)},0),f;if(void 0!==Va[a])Va[a].push({onLoad:b,onProgress:c,onError:d});else{var g=a.match(/^data:(.*?)(;base64)?,(.*)$/);if(g){c= -g[1];var h=!!g[2],g=g[3],g=window.decodeURIComponent(g);h&&(g=window.atob(g));try{var k=(this.responseType||"").toLowerCase();switch(k){case "arraybuffer":case "blob":for(var m=new Uint8Array(g.length),h=0;h=e)break a;else{f=b[1];a=e)break b}d=c;c=0}}for(;c>>1,ag;g++)if(d[g]===d[(g+1)%3]){a.push(f);break}for(f=a.length-1;0<=f;f--)for(d=a[f],this.faces.splice(d,1),c=0,e=this.faceVertexUvs.length;ca?b.copy(this.origin):b.copy(this.direction).multiplyScalar(a).add(this.origin)},distanceToPoint:function(a){return Math.sqrt(this.distanceSqToPoint(a))},distanceSqToPoint:function(){var a=new p;return function(b){var c= +a.subVectors(b,this.origin).dot(this.direction);if(0>c)return this.origin.distanceToSquared(b);a.copy(this.direction).multiplyScalar(c).add(this.origin);return a.distanceToSquared(b)}}(),distanceSqToSegment:function(){var a=new p,b=new p,c=new p;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),m=c.dot(this.direction),l=-c.dot(b),n=c.lengthSq(),p=Math.abs(1-k*k);if(0=-r?e<=r?(h=1/p,d*=h,e*=h,k=d*(d+k*e+2*m)+e*(k*d+e+2*l)+n):(e=h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):(e=-h,d=Math.max(0,-(k*e+m)),k=-d*d+e*(e+2*l)+n):e<=-r?(d=Math.max(0,-(-k*h+m)),e=0b)return null;b=Math.sqrt(b-e);e=d-b;d+=b;return 0>e&&0>d?null:0>e?this.at(d,c):this.at(e,c)}}(),intersectsSphere:function(a){return this.distanceToPoint(a.center)<=a.radius},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){a=this.distanceToPlane(a);return null===a?null:this.at(a,b)},intersectsPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},intersectBox:function(a,b){var c=1/this.direction.x;var d=1/this.direction.y;var e=1/this.direction.z,f=this.origin;if(0<=c){var g=(a.min.x-f.x)*c;c*=a.max.x-f.x}else g=(a.max.x-f.x)*c,c*=a.min.x-f.x;if(0<=d){var h=(a.min.y- +f.y)*d;d*=a.max.y-f.y}else h=(a.max.y-f.y)*d,d*=a.min.y-f.y;if(g>d||h>c)return null;if(h>g||g!==g)g=h;if(da||h>c)return null;if(h>g||g!==g)g=h;if(ac?null:this.at(0<=g?g:c,b)},intersectsBox:function(){var a=new p;return function(b){return null!==this.intersectBox(b,a)}}(),intersectTriangle:function(){var a=new p,b=new p,c=new p,d=new p;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));if(0>g||e+g>f)return null;e=-h*a.dot(d);return 0>e?null:this.at(e/f,k)}}(),applyMatrix4:function(a){this.origin.applyMatrix4(a);this.direction.transformDirection(a);return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}}); +Object.assign(Nb.prototype,{set:function(a,b){this.start.copy(a);this.end.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},getCenter:function(a){return(a||new p).addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){return(a||new p).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){b=b||new p;return this.delta(b).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(){var a=new p,b=new p;return function(c,d){a.subVectors(c,this.start);b.subVectors(this.end,this.start);c=b.dot(b);c=b.dot(a)/c;d&&(c=Q.clamp(c,0,1));return c}}(),closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);c=c||new p;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)}});Object.assign(Za,{normal:function(){var a=new p;return function(b,c,d,e){e=e||new p;e.subVectors(d,c);a.subVectors(b,c);e.cross(a);b=e.lengthSq();return 0=b.x+b.y}}()});Object.assign(Za.prototype,{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},clone:function(){return(new this.constructor).copy(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 p,b=new p;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 p).addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},normal:function(a){return Za.normal(this.a,this.b,this.c,a)},plane:function(a){return(a||new Ea).setFromCoplanarPoints(this.a,this.b,this.c)},barycoordFromPoint:function(a,b){return Za.barycoordFromPoint(a, +this.a,this.b,this.c,b)},containsPoint:function(a){return Za.containsPoint(a,this.a,this.b,this.c)},closestPointToPoint:function(){var a=new Ea,b=[new Nb,new Nb,new Nb],c=new p,d=new p;return function(e,f){f=f||new p;var g=Infinity;a.setFromCoplanarPoints(this.a,this.b,this.c);a.projectPoint(e,c);if(!0===this.containsPoint(c))f.copy(c);else for(b[0].set(this.a,this.b),b[1].set(this.b,this.c),b[2].set(this.c,this.a),e=0;ec.far?null:{distance:b, +point:z.clone(),object:a}}function c(c,d,e,f,m,l,q,n){g.fromBufferAttribute(f,l);h.fromBufferAttribute(f,q);k.fromBufferAttribute(f,n);if(c=b(c,c.material,d,e,g,h,k,w))m&&(u.fromBufferAttribute(m,l),r.fromBufferAttribute(m,q),t.fromBufferAttribute(m,n),c.uv=a(w,g,h,k,u,r,t)),c.face=new Ya(l,q,n,Za.normal(g,h,k)),c.faceIndex=l;return c}var d=new O,e=new sb,f=new Ia,g=new p,h=new p,k=new p,m=new p,l=new p,n=new p,u=new D,r=new D,t=new D,v=new p,w=new p,z=new p;return function(q,p){var v=this.geometry, +z=this.material,y=this.matrixWorld;if(void 0!==z&&(null===v.boundingSphere&&v.computeBoundingSphere(),f.copy(v.boundingSphere),f.applyMatrix4(y),!1!==q.ray.intersectsSphere(f)&&(d.getInverse(y),e.copy(q.ray).applyMatrix4(d),null===v.boundingBox||!1!==e.intersectsBox(v.boundingBox)))){var x;if(v.isBufferGeometry){var z=v.index,B=v.attributes.position,y=v.attributes.uv,D;if(null!==z){var C=0;for(D=z.count;Cf||(f=d.ray.origin.distanceTo(a),fd.far||e.push({distance:f,point:a.clone(),face:null,object:this}))}}(),clone:function(){return(new this.constructor(this.material)).copy(this)}}); +Dc.prototype=Object.assign(Object.create(x.prototype),{constructor:Dc,copy:function(a){x.prototype.copy.call(this,a,!1);a=a.levels;for(var b=0,c=a.length;b=d[e].distance)d[e-1].object.visible=!1,d[e].object.visible=!0;else break; +for(;ef||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l),ud.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}));else for(g=0,v=r.length/3-1;gf||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l),ud.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld),index:g,face:null,faceIndex:null,object:this}))}else if(g.isGeometry)for(k=g.vertices,m=k.length,g=0;gf||(l.applyMatrix4(this.matrixWorld),u=d.ray.origin.distanceTo(l),ud.far||e.push({distance:u,point:h.clone().applyMatrix4(this.matrixWorld), +index:g,face:null,faceIndex:null,object:this}))}}}(),clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});X.prototype=Object.assign(Object.create(sa.prototype),{constructor:X,isLineSegments:!0});yd.prototype=Object.assign(Object.create(sa.prototype),{constructor:yd,isLineLoop:!0});Ka.prototype=Object.create(P.prototype);Ka.prototype.constructor=Ka;Ka.prototype.isPointsMaterial=!0;Ka.prototype.copy=function(a){P.prototype.copy.call(this,a);this.color.copy(a.color); +this.map=a.map;this.size=a.size;this.sizeAttenuation=a.sizeAttenuation;return this};Rb.prototype=Object.assign(Object.create(x.prototype),{constructor:Rb,isPoints:!0,raycast:function(){var a=new O,b=new sb,c=new Ia;return function(d,e){function f(a,c){var f=b.distanceSqToPoint(a);if(fd.far||e.push({distance:h,distanceToRay:Math.sqrt(f),point:a.clone(),index:c,face:null,object:g})}}var g=this,h=this.geometry, +k=this.matrixWorld,m=d.params.Points.threshold;null===h.boundingSphere&&h.computeBoundingSphere();c.copy(h.boundingSphere);c.applyMatrix4(k);c.radius+=m;if(!1!==d.ray.intersectsSphere(c)){a.getInverse(k);b.copy(d.ray).applyMatrix4(a);var m=m/((this.scale.x+this.scale.y+this.scale.z)/3),l=m*m,m=new p;if(h.isBufferGeometry){var n=h.index,h=h.attributes.position.array;if(null!==n)for(var u=n.array,n=0,r=u.length;n=a.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}});Sb.prototype=Object.create(U.prototype);Sb.prototype.constructor=Sb;Sb.prototype.isCompressedTexture= +!0;Gc.prototype=Object.create(U.prototype);Gc.prototype.constructor=Gc;Gc.prototype.isDepthTexture=!0;Tb.prototype=Object.create(E.prototype);Tb.prototype.constructor=Tb;Hc.prototype=Object.create(L.prototype);Hc.prototype.constructor=Hc;Ub.prototype=Object.create(E.prototype);Ub.prototype.constructor=Ub;Ic.prototype=Object.create(L.prototype);Ic.prototype.constructor=Ic;ja.prototype=Object.create(E.prototype);ja.prototype.constructor=ja;Jc.prototype=Object.create(L.prototype);Jc.prototype.constructor= +Jc;Vb.prototype=Object.create(ja.prototype);Vb.prototype.constructor=Vb;Kc.prototype=Object.create(L.prototype);Kc.prototype.constructor=Kc;ub.prototype=Object.create(ja.prototype);ub.prototype.constructor=ub;Lc.prototype=Object.create(L.prototype);Lc.prototype.constructor=Lc;Wb.prototype=Object.create(ja.prototype);Wb.prototype.constructor=Wb;Mc.prototype=Object.create(L.prototype);Mc.prototype.constructor=Mc;Xb.prototype=Object.create(ja.prototype);Xb.prototype.constructor=Xb;Nc.prototype=Object.create(L.prototype); +Nc.prototype.constructor=Nc;Yb.prototype=Object.create(E.prototype);Yb.prototype.constructor=Yb;Oc.prototype=Object.create(L.prototype);Oc.prototype.constructor=Oc;Zb.prototype=Object.create(E.prototype);Zb.prototype.constructor=Zb;Pc.prototype=Object.create(L.prototype);Pc.prototype.constructor=Pc;$b.prototype=Object.create(E.prototype);$b.prototype.constructor=$b;var Lg={triangulate:function(a,b,c){c=c||2;var d=b&&b.length,e=d?b[0]*c:a.length,f=bf(a,0,e,c,!0),g=[];if(!f)return g;var h;if(d){var k= +c,d=[],m;var l=0;for(m=b.length;l80*c){var r=h=a[0];var t=d=a[1];for(k=c;kh&&(h=l),b>d&&(d=b);h=Math.max(h-r,d-t);h=0!==h?1/h:0}Sc(f,g,c,r,t,h);return g}},$a={area:function(a){for(var b=a.length,c=0,d=b-1,e=0;e$a.area(a)},triangulateShape:function(a,b){function c(a){var b=a.length;2Number.EPSILON){var k=Math.sqrt(h),m=Math.sqrt(f*f+g*g),h=b.x-e/k;b=b.y+d/k;g=((c.x-g/m-h)*g-(c.y+f/m-b)*f)/(d*g-e*f);f=h+d*g-a.x;d=b+e*g-a.y;e=f*f+d*d;if(2>=e)return new D(f, +d);e=Math.sqrt(e/2)}else a=!1,d>Number.EPSILON?f>Number.EPSILON&&(a=!0):d<-Number.EPSILON?f<-Number.EPSILON&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(f=-e,e=Math.sqrt(h)):(f=d,d=e,e=Math.sqrt(h/2));return new D(f/e,d/e)}function e(a,b){for(G=a.length;0<=--G;){var c=G;var d=G-1;0>d&&(d=a.length-1);var e,f=x+2*w;for(e=0;eMath.abs(g-k)?[new D(a,1-c),new D(h,1-d),new D(m,1-e),new D(n,1-b)]:[new D(g,1-c),new D(k,1-d),new D(l,1-e),new D(p,1-b)]}};Uc.prototype=Object.create(L.prototype);Uc.prototype.constructor= +Uc;ac.prototype=Object.create(La.prototype);ac.prototype.constructor=ac;Vc.prototype=Object.create(L.prototype);Vc.prototype.constructor=Vc;wb.prototype=Object.create(E.prototype);wb.prototype.constructor=wb;Wc.prototype=Object.create(L.prototype);Wc.prototype.constructor=Wc;bc.prototype=Object.create(E.prototype);bc.prototype.constructor=bc;Xc.prototype=Object.create(L.prototype);Xc.prototype.constructor=Xc;cc.prototype=Object.create(E.prototype);cc.prototype.constructor=cc;xb.prototype=Object.create(L.prototype); +xb.prototype.constructor=xb;xb.prototype.toJSON=function(){var a=L.prototype.toJSON.call(this);return ff(this.parameters.shapes,a)};yb.prototype=Object.create(E.prototype);yb.prototype.constructor=yb;yb.prototype.toJSON=function(){var a=E.prototype.toJSON.call(this);return ff(this.parameters.shapes,a)};dc.prototype=Object.create(E.prototype);dc.prototype.constructor=dc;zb.prototype=Object.create(L.prototype);zb.prototype.constructor=zb;ab.prototype=Object.create(E.prototype);ab.prototype.constructor= +ab;Yc.prototype=Object.create(zb.prototype);Yc.prototype.constructor=Yc;Zc.prototype=Object.create(ab.prototype);Zc.prototype.constructor=Zc;$c.prototype=Object.create(L.prototype);$c.prototype.constructor=$c;ec.prototype=Object.create(E.prototype);ec.prototype.constructor=ec;var ka=Object.freeze({WireframeGeometry:Tb,ParametricGeometry:Hc,ParametricBufferGeometry:Ub,TetrahedronGeometry:Jc,TetrahedronBufferGeometry:Vb,OctahedronGeometry:Kc,OctahedronBufferGeometry:ub,IcosahedronGeometry:Lc,IcosahedronBufferGeometry:Wb, +DodecahedronGeometry:Mc,DodecahedronBufferGeometry:Xb,PolyhedronGeometry:Ic,PolyhedronBufferGeometry:ja,TubeGeometry:Nc,TubeBufferGeometry:Yb,TorusKnotGeometry:Oc,TorusKnotBufferGeometry:Zb,TorusGeometry:Pc,TorusBufferGeometry:$b,TextGeometry:Uc,TextBufferGeometry:ac,SphereGeometry:Vc,SphereBufferGeometry:wb,RingGeometry:Wc,RingBufferGeometry:bc,PlaneGeometry:Ac,PlaneBufferGeometry:rb,LatheGeometry:Xc,LatheBufferGeometry:cc,ShapeGeometry:xb,ShapeBufferGeometry:yb,ExtrudeGeometry:ib,ExtrudeBufferGeometry:La, +EdgesGeometry:dc,ConeGeometry:Yc,ConeBufferGeometry:Zc,CylinderGeometry:zb,CylinderBufferGeometry:ab,CircleGeometry:$c,CircleBufferGeometry:ec,BoxGeometry:Mb,BoxBufferGeometry:qb});fc.prototype=Object.create(P.prototype);fc.prototype.constructor=fc;fc.prototype.isShadowMaterial=!0;gc.prototype=Object.create(Fa.prototype);gc.prototype.constructor=gc;gc.prototype.isRawShaderMaterial=!0;Ua.prototype=Object.create(P.prototype);Ua.prototype.constructor=Ua;Ua.prototype.isMeshStandardMaterial=!0;Ua.prototype.copy= +function(a){P.prototype.copy.call(this,a);this.defines={STANDARD:""};this.color.copy(a.color);this.roughness=a.roughness;this.metalness=a.metalness;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale); +this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.roughnessMap=a.roughnessMap;this.metalnessMap=a.metalnessMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.envMapIntensity=a.envMapIntensity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets= +a.morphTargets;this.morphNormals=a.morphNormals;return this};Ab.prototype=Object.create(Ua.prototype);Ab.prototype.constructor=Ab;Ab.prototype.isMeshPhysicalMaterial=!0;Ab.prototype.copy=function(a){Ua.prototype.copy.call(this,a);this.defines={PHYSICAL:""};this.reflectivity=a.reflectivity;this.clearCoat=a.clearCoat;this.clearCoatRoughness=a.clearCoatRoughness;return this};Ma.prototype=Object.create(P.prototype);Ma.prototype.constructor=Ma;Ma.prototype.isMeshPhongMaterial=!0;Ma.prototype.copy=function(a){P.prototype.copy.call(this, +a);this.color.copy(a.color);this.specular.copy(a.specular);this.shininess=a.shininess;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale= +a.displacementScale;this.displacementBias=a.displacementBias;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Bb.prototype= +Object.create(Ma.prototype);Bb.prototype.constructor=Bb;Bb.prototype.isMeshToonMaterial=!0;Bb.prototype.copy=function(a){Ma.prototype.copy.call(this,a);this.gradientMap=a.gradientMap;return this};Cb.prototype=Object.create(P.prototype);Cb.prototype.constructor=Cb;Cb.prototype.isMeshNormalMaterial=!0;Cb.prototype.copy=function(a){P.prototype.copy.call(this,a);this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap; +this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Db.prototype=Object.create(P.prototype);Db.prototype.constructor=Db;Db.prototype.isMeshLambertMaterial=!0;Db.prototype.copy=function(a){P.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity= +a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin; +this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};Eb.prototype=Object.create(W.prototype);Eb.prototype.constructor=Eb;Eb.prototype.isLineDashedMaterial=!0;Eb.prototype.copy=function(a){W.prototype.copy.call(this,a);this.scale=a.scale;this.dashSize=a.dashSize;this.gapSize=a.gapSize;return this};var Mg=Object.freeze({ShadowMaterial:fc,SpriteMaterial:hb,RawShaderMaterial:gc,ShaderMaterial:Fa,PointsMaterial:Ka,MeshPhysicalMaterial:Ab,MeshStandardMaterial:Ua, +MeshPhongMaterial:Ma,MeshToonMaterial:Bb,MeshNormalMaterial:Cb,MeshLambertMaterial:Db,MeshDepthMaterial:eb,MeshDistanceMaterial:fb,MeshBasicMaterial:Aa,LineDashedMaterial:Eb,LineBasicMaterial:W,Material:P}),Ib={enabled:!1,files:{},add:function(a,b){!1!==this.enabled&&(this.files[a]=b)},get:function(a){if(!1!==this.enabled)return this.files[a]},remove:function(a){delete this.files[a]},clear:function(){this.files={}}},xa=new he,cb={};Object.assign(Na.prototype,{load:function(a,b,c,d){void 0===a&&(a= +"");void 0!==this.path&&(a=this.path+a);a=this.manager.resolveURL(a);var e=this,f=Ib.get(a);if(void 0!==f)return e.manager.itemStart(a),setTimeout(function(){b&&b(f);e.manager.itemEnd(a)},0),f;if(void 0!==cb[a])cb[a].push({onLoad:b,onProgress:c,onError:d});else{var g=a.match(/^data:(.*?)(;base64)?,(.*)$/);if(g){c=g[1];var h=!!g[2],g=g[3],g=window.decodeURIComponent(g);h&&(g=window.atob(g));try{var k=(this.responseType||"").toLowerCase();switch(k){case "arraybuffer":case "blob":for(var m=new Uint8Array(g.length), +h=0;hg)e=a+1;else if(0b&&(b=0);1Number.EPSILON&&(g.normalize(),c=Math.acos(Q.clamp(d[k-1].dot(d[k]),-1,1)),e[k].applyMatrix4(h.makeRotationAxis(g, +c))),f[k].crossVectors(d[k],e[k]);if(!0===b)for(c=Math.acos(Q.clamp(e[0].dot(e[a]),-1,1)),c/=a,0d;)d+=c;for(;d>c;)d-=c;de&&(e=1);1E-4>d&&(d=e);1E-4>k&&(k=e);Ee.initNonuniformCatmullRom(f.x,g.x,h.x,c.x,d,e,k);Fe.initNonuniformCatmullRom(f.y,g.y,h.y,c.y,d,e,k);Ge.initNonuniformCatmullRom(f.z, +g.z,h.z,c.z,d,e,k)}else"catmullrom"===this.curveType&&(Ee.initCatmullRom(f.x,g.x,h.x,c.x,this.tension),Fe.initCatmullRom(f.y,g.y,h.y,c.y,this.tension),Ge.initCatmullRom(f.z,g.z,h.z,c.z,this.tension));b.set(Ee.calc(a),Fe.calc(a),Ge.calc(a));return b};ca.prototype.copy=function(a){C.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;bc.length-2?c.length-1:a+1],c=c[a>c.length-3?c.length-1:a+2];b.set(hf(d,e.x,f.x, +g.x,c.x),hf(d,e.y,f.y,g.y,c.y));return b};Ra.prototype.copy=function(a){C.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;b=b)return b=c[a]-b,a=this.curves[a],c=a.getLength(),a.getPointAt(0===c?0:1-b/c);a++}return null},getLength:function(){var a=this.getCurveLengths();return a[a.length-1]},updateArcLengths:function(){this.needsUpdate=!0;this.cacheLengths=null;this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var a=[], +b=0,c=0,d=this.curves.length;c=e)break a;else{f=b[1];a=e)break b}d=c;c=0}}for(;c>>1,ab;)--f;++f;if(0!==e||f!==d)e>=f&&(f=Math.max(f,1),e=f-1),a=this.getValueSize(),this.times=da.arraySlice(c,e,f),this.values=da.arraySlice(this.values,e*a,f*a);return this},validate:function(){var a=!0,b=this.getValueSize();0!==b-Math.floor(b)&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),a=!1);var c=this.times,b=this.values, -d=c.length;0===d&&(console.error("THREE.KeyframeTrack: Track is empty.",this),a=!1);for(var e=null,f=0;f!==d;f++){var g=c[f];if("number"===typeof g&&isNaN(g)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,f,g);a=!1;break}if(null!==e&&e>g){console.error("THREE.KeyframeTrack: Out of order keys.",this,f,g,e);a=!1;break}e=g}if(void 0!==b&&da.isTypedArray(b))for(f=0,c=b.length;f!==c;++f)if(d=b[f],isNaN(d)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,f, -d);a=!1;break}return a},optimize:function(){for(var a,b,c=this.times,d=this.values,e=this.getValueSize(),f=2302===this.getInterpolation(),g=1,h=c.length-1,k=1;kb;)--f;++f;if(0!==e||f!==d)e>=f&&(f=Math.max(f,1),e=f-1),a=this.getValueSize(),this.times=ga.arraySlice(c,e,f),this.values=ga.arraySlice(this.values,e*a,f*a);return this},validate:function(){var a=!0,b=this.getValueSize();0!==b-Math.floor(b)&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),a=!1);var c=this.times,b=this.values, +d=c.length;0===d&&(console.error("THREE.KeyframeTrack: Track is empty.",this),a=!1);for(var e=null,f=0;f!==d;f++){var g=c[f];if("number"===typeof g&&isNaN(g)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,f,g);a=!1;break}if(null!==e&&e>g){console.error("THREE.KeyframeTrack: Out of order keys.",this,f,g,e);a=!1;break}e=g}if(void 0!==b&&ga.isTypedArray(b))for(f=0,c=b.length;f!==c;++f)if(d=b[f],isNaN(d)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,f, +d);a=!1;break}return a},optimize:function(){for(var a,b,c=this.times,d=this.values,e=this.getValueSize(),f=2302===this.getInterpolation(),g=1,h=c.length-1,k=1;km.opacity&&(m.transparent=!0);d.setTextures(k);return d.parse(m)}}()});var Ee={decodeText:function(a){if("undefined"!==typeof TextDecoder)return(new TextDecoder).decode(a);for(var b="",c=0,d=a.length;cm.opacity&&(m.transparent=!0);d.setTextures(k);return d.parse(m)}}()});var He={decodeText:function(a){if("undefined"!==typeof TextDecoder)return(new TextDecoder).decode(a);for(var b="",c=0,d=a.length;cf;f++){var A=h[r++]; -var B=x[2*A];A=x[2*A+1];B=new D(B,A);2!==f&&c.faceVertexUvs[e][v].push(B);0!==f&&c.faceVertexUvs[e][v+1].push(B)}}w&&(w=3*h[r++],t.normal.set(m[w++],m[w++],m[w]),y.normal.copy(t.normal));if(z)for(e=0;4>e;e++)w=3*h[r++],z=new p(m[w++],m[w++],m[w]),2!==e&&t.vertexNormals.push(z),0!==e&&y.vertexNormals.push(z);n&&(n=h[r++],n=l[n],t.color.setHex(n),y.color.setHex(n));if(k)for(e=0;4>e;e++)n=h[r++],n=l[n],2!==e&&t.vertexColors.push(new F(n)),0!==e&&y.vertexColors.push(new F(n));c.faces.push(t);c.faces.push(y)}else{t= -new Ra;t.a=h[r++];t.b=h[r++];t.c=h[r++];v&&(v=h[r++],t.materialIndex=v);v=c.faces.length;if(e)for(e=0;ef;f++)A=h[r++],B=x[2*A],A=x[2*A+1],B=new D(B,A),c.faceVertexUvs[e][v].push(B);w&&(w=3*h[r++],t.normal.set(m[w++],m[w++],m[w]));if(z)for(e=0;3>e;e++)w=3*h[r++],z=new p(m[w++],m[w++],m[w]),t.vertexNormals.push(z);n&&(n=h[r++],t.color.setHex(l[n]));if(k)for(e=0;3>e;e++)n=h[r++],t.vertexColors.push(new F(l[n]));c.faces.push(t)}}d=a;r=void 0!==d.influencesPerVertex? +0;ef;f++){var A=h[r++]; +var B=x[2*A];A=x[2*A+1];B=new D(B,A);2!==f&&c.faceVertexUvs[e][v].push(B);0!==f&&c.faceVertexUvs[e][v+1].push(B)}}w&&(w=3*h[r++],t.normal.set(m[w++],m[w++],m[w]),y.normal.copy(t.normal));if(z)for(e=0;4>e;e++)w=3*h[r++],z=new p(m[w++],m[w++],m[w]),2!==e&&t.vertexNormals.push(z),0!==e&&y.vertexNormals.push(z);n&&(n=h[r++],n=l[n],t.color.setHex(n),y.color.setHex(n));if(k)for(e=0;4>e;e++)n=h[r++],n=l[n],2!==e&&t.vertexColors.push(new H(n)),0!==e&&y.vertexColors.push(new H(n));c.faces.push(t);c.faces.push(y)}else{t= +new Ya;t.a=h[r++];t.b=h[r++];t.c=h[r++];v&&(v=h[r++],t.materialIndex=v);v=c.faces.length;if(e)for(e=0;ef;f++)A=h[r++],B=x[2*A],A=x[2*A+1],B=new D(B,A),c.faceVertexUvs[e][v].push(B);w&&(w=3*h[r++],t.normal.set(m[w++],m[w++],m[w]));if(z)for(e=0;3>e;e++)w=3*h[r++],z=new p(m[w++],m[w++],m[w]),t.vertexNormals.push(z);n&&(n=h[r++],t.color.setHex(l[n]));if(k)for(e=0;3>e;e++)n=h[r++],t.vertexColors.push(new H(l[n]));c.faces.push(t)}}d=a;r=void 0!==d.influencesPerVertex? d.influencesPerVertex:2;if(d.skinWeights)for(g=0,h=d.skinWeights.length;gg)e=a+1;else if(0b&&(b=0);1Number.EPSILON&&(g.normalize(),c=Math.acos(O.clamp(d[k-1].dot(d[k]),-1,1)),e[k].applyMatrix4(h.makeRotationAxis(g,c))),f[k].crossVectors(d[k],e[k]);if(!0===b)for(c=Math.acos(O.clamp(e[0].dot(e[a]),-1,1)),c/=a,0=b)return b=c[a]-b,a=this.curves[a],c=a.getLength(),a.getPointAt(0===c?0:1-b/c);a++}return null},getLength:function(){var a= -this.getCurveLengths();return a[a.length-1]},updateArcLengths:function(){this.needsUpdate=!0;this.cacheLengths=null;this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var a=[],b=0,c=0,d=this.curves.length;cd;)d+=c;for(;d>c;)d-=c;dc.length-2?c.length-1:a+1],c=c[a>c.length-3?c.length-1:a+2];b.set(hf(d,e.x,f.x,g.x,c.x),hf(d,e.y,f.y,g.y,c.y));return b};bb.prototype.copy=function(a){P.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;b -Number.EPSILON){if(0>m&&(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=Ta.isClockWise,f=this.subPaths;if(0===f.length)return[];if(!0===b)return c(f);b=[];if(1===f.length){var g=f[0];var h=new Bb;h.curves=g.curves;b.push(h);return b}var k=!e(f[0].getPoints()),k=a?!k:k;h=[];var m=[],l=[],n=0;m[n]=void 0;l[n]=[];for(var p= -0,r=f.length;pd&&this._mixBufferRegion(c,a,3*b,1-d,b);for(var d=b,f=b+b;d!==f;++d)if(c[d]!==c[d+b]){e.setValue(c,a);break}},saveOriginalState:function(){var a=this.buffer,b=this.valueSize,c=3*b;this.binding.getValue(a,c);for(var d=b;d!==c;++d)a[d]=a[c+d%b];this.cumulativeWeight=0},restoreOriginalState:function(){this.binding.setValue(this.buffer,3*this.valueSize)},_select:function(a,b,c,d,e){if(.5<=d)for(d= -0;d!==e;++d)a[b+d]=a[c+d]},_slerp:function(a,b,c,d){ha.slerpFlat(a,b,a,b,a,c,d)},_lerp:function(a,b,c,d,e){for(var f=1-d,g=0;g!==e;++g){var h=b+g;a[h]=a[h]*f+a[c+g]*d}}});Object.assign(lf.prototype,{getValue:function(a,b){this.bind();var c=this._bindings[this._targetGroup.nCachedObjects_];void 0!==c&&c.getValue(a,b)},setValue:function(a,b){for(var c=this._bindings,d=this._targetGroup.nCachedObjects_,e=c.length;d!==e;++d)c[d].setValue(a,b)},bind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_, -c=a.length;b!==c;++b)a[b].bind()},unbind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].unbind()}});Object.assign(ga,{Composite:lf,create:function(a,b,c){return a&&a.isAnimationObjectGroup?new ga.Composite(a,b,c):new ga(a,b,c)},sanitizeNodeName:function(a){return a.replace(/\s/g,"_").replace(/[^\w-]/g,"")},parseTrackName:function(){var a=new RegExp("^"+/((?:[\w-]+[\/:])*)/.source+/([\w-\.]+)?/.source+/(?:\.([\w-]+)(?:\[(.+)\])?)?/.source+/\.([\w-]+)(?:\[(.+)\])?/.source+ -"$"),b=["material","materials","bones"];return function(c){var d=a.exec(c);if(!d)throw Error("PropertyBinding: Cannot parse trackName: "+c);var d={nodeName:d[2],objectName:d[3],objectIndex:d[4],propertyName:d[5],propertyIndex:d[6]},e=d.nodeName&&d.nodeName.lastIndexOf(".");if(void 0!==e&&-1!==e){var f=d.nodeName.substring(e+1);-1!==b.indexOf(f)&&(d.nodeName=d.nodeName.substring(0,e),d.objectName=f)}if(null===d.propertyName||0===d.propertyName.length)throw Error("PropertyBinding: can not parse propertyName from trackName: "+ -c);return d}}(),findNode:function(a,b){if(!b||""===b||"root"===b||"."===b||-1===b||b===a.name||b===a.uuid)return a;if(a.skeleton){var c=function(a){for(var c=0;c=b){var l=b++,n=a[l];c[n.uuid]=m;a[m]=n;c[k]=l;a[l]=h;h=0;for(k=e;h!==k;++h){var n=d[h],p= -n[m];n[m]=n[l];n[l]=p}}}this.nCachedObjects_=b},uncache:function(){for(var a,b,c=this._objects,d=c.length,e=this.nCachedObjects_,f=this._indicesByUUID,g=this._bindings,h=g.length,k=0,m=arguments.length;k!==m;++k){b=arguments[k].uuid;var l=f[b];if(void 0!==l)if(delete f[b],lb||0===c)return;this._startTime=null;b*=c}b*=this._updateTimeScale(a);c=this._updateTime(b);a=this._updateWeight(a);if(0c.parameterPositions[1]&&(this.stopFading(),0===d&&(this.enabled=!1))}}return this._effectiveWeight=b},_updateTimeScale:function(a){var b=0;if(!this.paused){var b=this.timeScale,c=this._timeScaleInterpolant;if(null!==c){var d=c.evaluate(a)[0], -b=b*d;a>c.parameterPositions[1]&&(this.stopWarping(),0===b?this.paused=!0:this.timeScale=b)}}return this._effectiveTimeScale=b},_updateTime:function(a){var b=this.time+a;if(0===a)return b;var c=this._clip.duration,d=this.loop,e=this._loopCount;if(2200===d)a:{if(-1===e&&(this._loopCount=0,this._setEndings(!0,!0,!1)),b>=c)b=c;else if(0>b)b=0;else break a;this.clampWhenFinished?this.paused=!0:this.enabled=!1;this._mixer.dispatchEvent({type:"finished",action:this,direction:0>a?-1:1})}else{d=2202===d; --1===e&&(0<=a?(e=0,this._setEndings(!0,0===this.repetitions,d)):this._setEndings(0===this.repetitions,!0,d));if(b>=c||0>b){var f=Math.floor(b/c),b=b-c*f,e=e+Math.abs(f),g=this.repetitions-e;0>g?(this.clampWhenFinished?this.paused=!0:this.enabled=!1,b=0a,this._setEndings(a,!a,d)):this._setEndings(!1,!1,d),this._loopCount=e,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:f}))}if(d&&1===(e&1))return this.time= -b,c-b}return this.time=b},_setEndings:function(a,b,c){var d=this._interpolantSettings;c?(d.endingStart=2401,d.endingEnd=2401):(d.endingStart=a?this.zeroSlopeAtStart?2401:2400:2402,d.endingEnd=b?this.zeroSlopeAtEnd?2401:2400:2402)},_scheduleFading:function(a,b,c){var d=this._mixer,e=d.time,f=this._weightInterpolant;null===f&&(this._weightInterpolant=f=d._lendControlInterpolant());d=f.parameterPositions;f=f.sampleValues;d[0]=e;f[0]=b;d[1]=e+a;f[1]=c;return this}});ve.prototype=Object.assign(Object.create(xa.prototype), -{constructor:ve,_bindAction:function(a,b){var c=a._localRoot||this._root,d=a._clip.tracks,e=d.length,f=a._propertyBindings;a=a._interpolants;var g=c.uuid,h=this._bindingsByRootAndName,k=h[g];void 0===k&&(k={},h[g]=k);for(h=0;h!==e;++h){var l=d[h],p=l.name,n=k[p];if(void 0===n){n=f[h];if(void 0!==n){null===n._cacheIndex&&(++n.referenceCount,this._addInactiveBinding(n,g,p));continue}n=new ue(ga.create(c,p,b&&b._propertyBindings[h].binding.parsedPath),l.ValueTypeName,l.getValueSize());++n.referenceCount; -this._addInactiveBinding(n,g,p)}f[h]=n;a[h].resultBuffer=n.buffer}},_activateAction:function(a){if(!this._isActiveAction(a)){if(null===a._cacheIndex){var b=(a._localRoot||this._root).uuid,c=a._clip.uuid,d=this._actionsByClip[c];this._bindAction(a,d&&d.knownActions[0]);this._addInactiveAction(a,c,b)}b=a._propertyBindings;c=0;for(d=b.length;c!==d;++c){var e=b[c];0===e.useCount++&&(this._lendBinding(e),e.saveOriginalState())}this._lendAction(a)}},_deactivateAction:function(a){if(this._isActiveAction(a)){for(var b= -a._propertyBindings,c=0,d=b.length;c!==d;++c){var e=b[c];0===--e.useCount&&(e.restoreOriginalState(),this._takeBackBinding(e))}this._takeBackAction(a)}},_initMemoryManager:function(){this._actions=[];this._nActiveActions=0;this._actionsByClip={};this._bindings=[];this._nActiveBindings=0;this._bindingsByRootAndName={};this._controlInterpolants=[];this._nActiveControlInterpolants=0;var a=this;this.stats={actions:{get total(){return a._actions.length},get inUse(){return a._nActiveActions}},bindings:{get total(){return a._bindings.length}, -get inUse(){return a._nActiveBindings}},controlInterpolants:{get total(){return a._controlInterpolants.length},get inUse(){return a._nActiveControlInterpolants}}}},_isActiveAction:function(a){a=a._cacheIndex;return null!==a&&aMath.abs(b)&&(b=1E-8);this.scale.set(.5*this.size,.5*this.size,b);this.lookAt(this.plane.normal);x.prototype.updateMatrixWorld.call(this,a)};var Sd,Be;Db.prototype=Object.create(x.prototype);Db.prototype.constructor=Db;Db.prototype.setDirection=function(){var a=new p,b;return function(c){.99999c.y?this.quaternion.set(1, -0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();Db.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,Math.max(0,a-b),1);this.line.updateMatrix();this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};Db.prototype.setColor=function(a){this.line.material.color.copy(a);this.cone.material.color.copy(a)};md.prototype=Object.create(X.prototype);md.prototype.constructor=md;var Ud=new p, -Fe=new Ce,Ge=new Ce,He=new Ce;Aa.prototype=Object.create(P.prototype);Aa.prototype.constructor=Aa;Aa.prototype.isCatmullRomCurve3=!0;Aa.prototype.getPoint=function(a,b){b=b||new p;var c=this.points,d=c.length;a*=d-(this.closed?0:1);var e=Math.floor(a);a-=e;this.closed?e+=0e&&(e=1);1E-4>d&&(d=e);1E-4>k&&(k=e);Fe.initNonuniformCatmullRom(f.x,g.x,h.x,c.x,d,e,k);Ge.initNonuniformCatmullRom(f.y,g.y,h.y,c.y,d,e,k);He.initNonuniformCatmullRom(f.z,g.z,h.z,c.z,d,e,k)}else"catmullrom"===this.curveType&&(Fe.initCatmullRom(f.x,g.x,h.x, -c.x,this.tension),Ge.initCatmullRom(f.y,g.y,h.y,c.y,this.tension),He.initCatmullRom(f.z,g.z,h.z,c.z,this.tension));b.set(Fe.calc(a),Ge.calc(a),He.calc(a));return b};Aa.prototype.copy=function(a){P.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;bNumber.EPSILON){if(0>m&&(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=$a.isClockWise,f=this.subPaths;if(0===f.length)return[];if(!0===b)return c(f);b=[];if(1=== +f.length){var g=f[0];var h=new jb;h.curves=g.curves;b.push(h);return b}var k=!e(f[0].getPoints()),k=a?!k:k;h=[];var m=[],l=[],n=0;m[n]=void 0;l[n]=[];for(var p=0,r=f.length;pd&&this._mixBufferRegion(c,a,3*b,1-d,b);for(var d=b,f=b+b;d!==f;++d)if(c[d]!==c[d+b]){e.setValue(c,a);break}}, +saveOriginalState:function(){var a=this.buffer,b=this.valueSize,c=3*b;this.binding.getValue(a,c);for(var d=b;d!==c;++d)a[d]=a[c+d%b];this.cumulativeWeight=0},restoreOriginalState:function(){this.binding.setValue(this.buffer,3*this.valueSize)},_select:function(a,b,c,d,e){if(.5<=d)for(d=0;d!==e;++d)a[b+d]=a[c+d]},_slerp:function(a,b,c,d){ha.slerpFlat(a,b,a,b,a,c,d)},_lerp:function(a,b,c,d,e){for(var f=1-d,g=0;g!==e;++g){var h=b+g;a[h]=a[h]*f+a[c+g]*d}}});Object.assign(mf.prototype,{getValue:function(a, +b){this.bind();var c=this._bindings[this._targetGroup.nCachedObjects_];void 0!==c&&c.getValue(a,b)},setValue:function(a,b){for(var c=this._bindings,d=this._targetGroup.nCachedObjects_,e=c.length;d!==e;++d)c[d].setValue(a,b)},bind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].bind()},unbind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].unbind()}});Object.assign(qa,{Composite:mf,create:function(a, +b,c){return a&&a.isAnimationObjectGroup?new qa.Composite(a,b,c):new qa(a,b,c)},sanitizeNodeName:function(a){return a.replace(/\s/g,"_").replace(/[^\w-]/g,"")},parseTrackName:function(){var a=new RegExp("^"+/((?:[\w-]+[\/:])*)/.source+/([\w-\.]+)?/.source+/(?:\.([\w-]+)(?:\[(.+)\])?)?/.source+/\.([\w-]+)(?:\[(.+)\])?/.source+"$"),b=["material","materials","bones"];return function(c){var d=a.exec(c);if(!d)throw Error("PropertyBinding: Cannot parse trackName: "+c);var d={nodeName:d[2],objectName:d[3], +objectIndex:d[4],propertyName:d[5],propertyIndex:d[6]},e=d.nodeName&&d.nodeName.lastIndexOf(".");if(void 0!==e&&-1!==e){var f=d.nodeName.substring(e+1);-1!==b.indexOf(f)&&(d.nodeName=d.nodeName.substring(0,e),d.objectName=f)}if(null===d.propertyName||0===d.propertyName.length)throw Error("PropertyBinding: can not parse propertyName from trackName: "+c);return d}}(),findNode:function(a,b){if(!b||""===b||"root"===b||"."===b||-1===b||b===a.name||b===a.uuid)return a;if(a.skeleton){var c=function(a){for(var c= +0;c=b){var l=b++,n=a[l];c[n.uuid]=m;a[m]=n;c[k]=l;a[l]=h;h=0;for(k=e;h!==k;++h){var n=d[h],p=n[m];n[m]=n[l];n[l]=p}}}this.nCachedObjects_=b},uncache:function(){for(var a,b,c=this._objects,d=c.length,e=this.nCachedObjects_,f=this._indicesByUUID,g=this._bindings,h=g.length,k=0,m=arguments.length;k!==m;++k){b=arguments[k].uuid;var l= +f[b];if(void 0!==l)if(delete f[b],lb||0===c)return;this._startTime=null;b*=c}b*=this._updateTimeScale(a);c=this._updateTime(b);a=this._updateWeight(a);if(0c.parameterPositions[1]&&(this.stopFading(),0===d&&(this.enabled=!1))}}return this._effectiveWeight=b},_updateTimeScale:function(a){var b=0;if(!this.paused){var b=this.timeScale,c=this._timeScaleInterpolant;if(null!==c){var d=c.evaluate(a)[0],b=b*d;a>c.parameterPositions[1]&&(this.stopWarping(),0===b?this.paused=!0:this.timeScale=b)}}return this._effectiveTimeScale=b},_updateTime:function(a){var b=this.time+a;if(0===a)return b;var c=this._clip.duration,d=this.loop,e=this._loopCount;if(2200=== +d)a:{if(-1===e&&(this._loopCount=0,this._setEndings(!0,!0,!1)),b>=c)b=c;else if(0>b)b=0;else break a;this.clampWhenFinished?this.paused=!0:this.enabled=!1;this._mixer.dispatchEvent({type:"finished",action:this,direction:0>a?-1:1})}else{d=2202===d;-1===e&&(0<=a?(e=0,this._setEndings(!0,0===this.repetitions,d)):this._setEndings(0===this.repetitions,!0,d));if(b>=c||0>b){var f=Math.floor(b/c),b=b-c*f,e=e+Math.abs(f),g=this.repetitions-e;0>g?(this.clampWhenFinished?this.paused=!0:this.enabled=!1,b=0a,this._setEndings(a,!a,d)):this._setEndings(!1,!1,d),this._loopCount=e,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:f}))}if(d&&1===(e&1))return this.time=b,c-b}return this.time=b},_setEndings:function(a,b,c){var d=this._interpolantSettings;c?(d.endingStart=2401,d.endingEnd=2401):(d.endingStart=a?this.zeroSlopeAtStart?2401:2400:2402,d.endingEnd=b?this.zeroSlopeAtEnd?2401:2400:2402)},_scheduleFading:function(a, +b,c){var d=this._mixer,e=d.time,f=this._weightInterpolant;null===f&&(this._weightInterpolant=f=d._lendControlInterpolant());d=f.parameterPositions;f=f.sampleValues;d[0]=e;f[0]=b;d[1]=e+a;f[1]=c;return this}});we.prototype=Object.assign(Object.create(za.prototype),{constructor:we,_bindAction:function(a,b){var c=a._localRoot||this._root,d=a._clip.tracks,e=d.length,f=a._propertyBindings;a=a._interpolants;var g=c.uuid,h=this._bindingsByRootAndName,k=h[g];void 0===k&&(k={},h[g]=k);for(h=0;h!==e;++h){var m= +d[h],l=m.name,n=k[l];if(void 0===n){n=f[h];if(void 0!==n){null===n._cacheIndex&&(++n.referenceCount,this._addInactiveBinding(n,g,l));continue}n=new ve(qa.create(c,l,b&&b._propertyBindings[h].binding.parsedPath),m.ValueTypeName,m.getValueSize());++n.referenceCount;this._addInactiveBinding(n,g,l)}f[h]=n;a[h].resultBuffer=n.buffer}},_activateAction:function(a){if(!this._isActiveAction(a)){if(null===a._cacheIndex){var b=(a._localRoot||this._root).uuid,c=a._clip.uuid,d=this._actionsByClip[c];this._bindAction(a, +d&&d.knownActions[0]);this._addInactiveAction(a,c,b)}b=a._propertyBindings;c=0;for(d=b.length;c!==d;++c){var e=b[c];0===e.useCount++&&(this._lendBinding(e),e.saveOriginalState())}this._lendAction(a)}},_deactivateAction:function(a){if(this._isActiveAction(a)){for(var b=a._propertyBindings,c=0,d=b.length;c!==d;++c){var e=b[c];0===--e.useCount&&(e.restoreOriginalState(),this._takeBackBinding(e))}this._takeBackAction(a)}},_initMemoryManager:function(){this._actions=[];this._nActiveActions=0;this._actionsByClip= +{};this._bindings=[];this._nActiveBindings=0;this._bindingsByRootAndName={};this._controlInterpolants=[];this._nActiveControlInterpolants=0;var a=this;this.stats={actions:{get total(){return a._actions.length},get inUse(){return a._nActiveActions}},bindings:{get total(){return a._bindings.length},get inUse(){return a._nActiveBindings}},controlInterpolants:{get total(){return a._controlInterpolants.length},get inUse(){return a._nActiveControlInterpolants}}}},_isActiveAction:function(a){a=a._cacheIndex; +return null!==a&&aMath.abs(b)&&(b=1E-8);this.scale.set(.5*this.size,.5*this.size,b);this.lookAt(this.plane.normal); +x.prototype.updateMatrixWorld.call(this,a)};var Sd,Ce;Hb.prototype=Object.create(x.prototype);Hb.prototype.constructor=Hb;Hb.prototype.setDirection=function(){var a=new p,b;return function(c){.99999c.y?this.quaternion.set(1,0,0,0):(a.set(c.z,0,-c.x).normalize(),b=Math.acos(c.y),this.quaternion.setFromAxisAngle(a,b))}}();Hb.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,Math.max(0,a-b),1);this.line.updateMatrix(); +this.cone.scale.set(c,b,c);this.cone.position.y=a;this.cone.updateMatrix()};Hb.prototype.setColor=function(a){this.line.material.color.copy(a);this.cone.material.color.copy(a)};nd.prototype=Object.create(X.prototype);nd.prototype.constructor=nd;C.create=function(a,b){console.log("THREE.Curve.create() has been deprecated");a.prototype=Object.create(C.prototype);a.prototype.constructor=a;a.prototype.getPoint=b;return a};Object.assign(bb.prototype,{createPointsGeometry:function(a){console.warn("THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead."); a=this.getPoints(a);return this.createGeometry(a)},createSpacedPointsGeometry:function(a){console.warn("THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.");a=this.getSpacedPoints(a);return this.createGeometry(a)},createGeometry:function(a){console.warn("THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.");for(var b=new L,c=0,d=a.length;c 0 ) output.geometries = geometries; if ( materials.length > 0 ) output.materials = materials; if ( textures.length > 0 ) output.textures = textures; if ( images.length > 0 ) output.images = images; + if ( shapes.length > 0 ) output.shapes = shapes; } @@ -28897,6 +28924,16 @@ function ShapeGeometry( shapes, curveSegments ) { ShapeGeometry.prototype = Object.create( Geometry.prototype ); ShapeGeometry.prototype.constructor = ShapeGeometry; +ShapeGeometry.prototype.toJSON = function () { + + var data = Geometry.prototype.toJSON.call( this ); + + var shapes = this.parameters.shapes; + + return toJSON( shapes, data ); + +}; + // ShapeBufferGeometry function ShapeBufferGeometry( shapes, curveSegments ) { @@ -29032,6 +29069,42 @@ function ShapeBufferGeometry( shapes, curveSegments ) { ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; +ShapeBufferGeometry.prototype.toJSON = function () { + + var data = BufferGeometry.prototype.toJSON.call( this ); + + var shapes = this.parameters.shapes; + + return toJSON( shapes, data ); + +}; + +// + +function toJSON( shapes, data ) { + + data.shapes = []; + + if ( Array.isArray( shapes ) ) { + + for ( var i = 0, l = shapes.length; i < l; i ++ ) { + + var shape = shapes[ i ]; + + data.shapes.push( shape.uuid ); + + } + + } else { + + data.shapes.push( shapes.uuid ); + + } + + return data; + +} + /** * @author WestLangley / http://github.com/WestLangley * @author Mugen87 / https://github.com/Mugen87 @@ -31293,2171 +31366,2254 @@ Object.assign( TextureLoader.prototype, { } ); /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ - -function Light( color, intensity ) { + * @author zz85 / http://www.lab4games.net/zz85/blog + * Extensible curve object + * + * Some common of curve methods: + * .getPoint( t, optionalTarget ), .getTangent( t ) + * .getPointAt( u, optionalTarget ), .getTangentAt( u ) + * .getPoints(), .getSpacedPoints() + * .getLength() + * .updateArcLengths() + * + * This following curves inherit from THREE.Curve: + * + * -- 2D curves -- + * THREE.ArcCurve + * THREE.CubicBezierCurve + * THREE.EllipseCurve + * THREE.LineCurve + * THREE.QuadraticBezierCurve + * THREE.SplineCurve + * + * -- 3D curves -- + * THREE.CatmullRomCurve3 + * THREE.CubicBezierCurve3 + * THREE.LineCurve3 + * THREE.QuadraticBezierCurve3 + * + * A series of curves can be represented as a THREE.CurvePath. + * + **/ - Object3D.call( this ); +/************************************************************** + * Abstract Curve base class + **************************************************************/ - this.type = 'Light'; +function Curve() { - this.color = new Color( color ); - this.intensity = intensity !== undefined ? intensity : 1; + this.type = 'Curve'; - this.receiveShadow = undefined; + this.arcLengthDivisions = 200; } -Light.prototype = Object.assign( Object.create( Object3D.prototype ), { +Object.assign( Curve.prototype, { - constructor: Light, + // Virtual base class method to overwrite and implement in subclasses + // - t [0 .. 1] - isLight: true, + getPoint: function ( /* t, optionalTarget */ ) { - copy: function ( source ) { + console.warn( 'THREE.Curve: .getPoint() not implemented.' ); + return null; - Object3D.prototype.copy.call( this, source ); + }, - this.color.copy( source.color ); - this.intensity = source.intensity; + // Get point at relative position in curve according to arc length + // - u [0 .. 1] - return this; + getPointAt: function ( u, optionalTarget ) { + + var t = this.getUtoTmapping( u ); + return this.getPoint( t, optionalTarget ); }, - toJSON: function ( meta ) { + // Get sequence of points using getPoint( t ) - var data = Object3D.prototype.toJSON.call( this, meta ); + getPoints: function ( divisions ) { - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; + if ( divisions === undefined ) divisions = 5; - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); + var points = []; - if ( this.distance !== undefined ) data.object.distance = this.distance; - if ( this.angle !== undefined ) data.object.angle = this.angle; - if ( this.decay !== undefined ) data.object.decay = this.decay; - if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; + for ( var d = 0; d <= divisions; d ++ ) { - if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); + points.push( this.getPoint( d / divisions ) ); - return data; + } - } + return points; -} ); + }, -/** - * @author alteredq / http://alteredqualia.com/ - */ + // Get sequence of points using getPointAt( u ) -function HemisphereLight( skyColor, groundColor, intensity ) { + getSpacedPoints: function ( divisions ) { - Light.call( this, skyColor, intensity ); + if ( divisions === undefined ) divisions = 5; - this.type = 'HemisphereLight'; + var points = []; - this.castShadow = undefined; + for ( var d = 0; d <= divisions; d ++ ) { - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + points.push( this.getPointAt( d / divisions ) ); - this.groundColor = new Color( groundColor ); + } -} + return points; -HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { + }, - constructor: HemisphereLight, + // Get total curve arc length - isHemisphereLight: true, + getLength: function () { - copy: function ( source ) { + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; - Light.prototype.copy.call( this, source ); + }, - this.groundColor.copy( source.groundColor ); + // Get list of cumulative segment lengths - return this; + getLengths: function ( divisions ) { - } + if ( divisions === undefined ) divisions = this.arcLengthDivisions; -} ); + if ( this.cacheArcLengths && + ( this.cacheArcLengths.length === divisions + 1 ) && + ! this.needsUpdate ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + return this.cacheArcLengths; -function LightShadow( camera ) { + } - this.camera = camera; + this.needsUpdate = false; - this.bias = 0; - this.radius = 1; + var cache = []; + var current, last = this.getPoint( 0 ); + var p, sum = 0; - this.mapSize = new Vector2( 512, 512 ); + cache.push( 0 ); - this.map = null; - this.matrix = new Matrix4(); + for ( p = 1; p <= divisions; p ++ ) { -} + current = this.getPoint( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; -Object.assign( LightShadow.prototype, { + } - copy: function ( source ) { + this.cacheArcLengths = cache; - this.camera = source.camera.clone(); + return cache; // { sums: cache, sum: sum }; Sum is in the last element. - this.bias = source.bias; - this.radius = source.radius; + }, - this.mapSize.copy( source.mapSize ); + updateArcLengths: function () { - return this; + this.needsUpdate = true; + this.getLengths(); }, - clone: function () { - - return new this.constructor().copy( this ); + // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant - }, + getUtoTmapping: function ( u, distance ) { - toJSON: function () { + var arcLengths = this.getLengths(); - var object = {}; + var i = 0, il = arcLengths.length; - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); + var targetArcLength; // The targeted u distance value to get - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; + if ( distance ) { - return object; + targetArcLength = distance; - } + } else { -} ); + targetArcLength = u * arcLengths[ il - 1 ]; -/** - * @author mrdoob / http://mrdoob.com/ - */ + } -function SpotLightShadow() { + // binary search for the index with largest value smaller than target u distance - LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); + var low = 0, high = il - 1, comparison; -} + while ( low <= high ) { -SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - constructor: SpotLightShadow, + comparison = arcLengths[ i ] - targetArcLength; - isSpotLightShadow: true, + if ( comparison < 0 ) { - update: function ( light ) { + low = i + 1; - var camera = this.camera; + } else if ( comparison > 0 ) { - var fov = _Math.RAD2DEG * 2 * light.angle; - var aspect = this.mapSize.width / this.mapSize.height; - var far = light.distance || camera.far; + high = i - 1; - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + } else { - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); + high = i; + break; - } + // DONE - } + } -} ); + } -/** - * @author alteredq / http://alteredqualia.com/ - */ + i = high; -function SpotLight( color, intensity, distance, angle, penumbra, decay ) { + if ( arcLengths[ i ] === targetArcLength ) { - Light.call( this, color, intensity ); + return i / ( il - 1 ); - this.type = 'SpotLight'; + } - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + // we could get finer grain at lengths, or use simple interpolation between two points - this.target = new Object3D(); + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; - Object.defineProperty( this, 'power', { - get: function () { + var segmentLength = lengthAfter - lengthBefore; - // intensity = power per solid angle. - // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - return this.intensity * Math.PI; + // determine where we are between the 'before' and 'after' points - }, - set: function ( power ) { + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - // intensity = power per solid angle. - // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - this.intensity = power / Math.PI; + // add that fractional amount to t - } - } ); + var t = ( i + segmentFraction ) / ( il - 1 ); - this.distance = ( distance !== undefined ) ? distance : 0; - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + return t; - this.shadow = new SpotLightShadow(); + }, -} + // Returns a unit vector tangent at t + // In case any sub curve does not implement its tangent derivation, + // 2 points a small delta apart will be used to find its gradient + // which seems to give a reasonable approximation -SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { + getTangent: function ( t ) { - constructor: SpotLight, + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; - isSpotLight: true, + // Capping in case of danger - copy: function ( source ) { + if ( t1 < 0 ) t1 = 0; + if ( t2 > 1 ) t2 = 1; - Light.prototype.copy.call( this, source ); + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; + var vec = pt2.clone().sub( pt1 ); + return vec.normalize(); - this.target = source.target.clone(); + }, - this.shadow = source.shadow.clone(); + getTangentAt: function ( u ) { - return this; + var t = this.getUtoTmapping( u ); + return this.getTangent( t ); - } + }, -} ); + computeFrenetFrames: function ( segments, closed ) { -/** - * @author mrdoob / http://mrdoob.com/ - */ + // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + var normal = new Vector3(); -function PointLight( color, intensity, distance, decay ) { + var tangents = []; + var normals = []; + var binormals = []; - Light.call( this, color, intensity ); + var vec = new Vector3(); + var mat = new Matrix4(); - this.type = 'PointLight'; + var i, u, theta; - Object.defineProperty( this, 'power', { - get: function () { + // compute the tangent vectors for each segment on the curve - // intensity = power per solid angle. - // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - return this.intensity * 4 * Math.PI; + for ( i = 0; i <= segments; i ++ ) { - }, - set: function ( power ) { + u = i / segments; - // intensity = power per solid angle. - // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - this.intensity = power / ( 4 * Math.PI ); + tangents[ i ] = this.getTangentAt( u ); + tangents[ i ].normalize(); } - } ); - this.distance = ( distance !== undefined ) ? distance : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + // select an initial normal vector perpendicular to the first tangent vector, + // and in the direction of the minimum tangent xyz component - this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); + normals[ 0 ] = new Vector3(); + binormals[ 0 ] = new Vector3(); + var min = Number.MAX_VALUE; + var tx = Math.abs( tangents[ 0 ].x ); + var ty = Math.abs( tangents[ 0 ].y ); + var tz = Math.abs( tangents[ 0 ].z ); -} + if ( tx <= min ) { -PointLight.prototype = Object.assign( Object.create( Light.prototype ), { + min = tx; + normal.set( 1, 0, 0 ); - constructor: PointLight, + } - isPointLight: true, + if ( ty <= min ) { - copy: function ( source ) { + min = ty; + normal.set( 0, 1, 0 ); - Light.prototype.copy.call( this, source ); + } - this.distance = source.distance; - this.decay = source.decay; + if ( tz <= min ) { - this.shadow = source.shadow.clone(); + normal.set( 0, 0, 1 ); - return this; + } - } + vec.crossVectors( tangents[ 0 ], normal ).normalize(); -} ); + normals[ 0 ].crossVectors( tangents[ 0 ], vec ); + binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); -/** - * @author mrdoob / http://mrdoob.com/ - */ -function DirectionalLightShadow( ) { + // compute the slowly-varying normal and binormal vectors for each segment on the curve - LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + for ( i = 1; i <= segments; i ++ ) { -} + normals[ i ] = normals[ i - 1 ].clone(); -DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + binormals[ i ] = binormals[ i - 1 ].clone(); - constructor: DirectionalLightShadow + vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); -} ); + if ( vec.length() > Number.EPSILON ) { -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + vec.normalize(); -function DirectionalLight( color, intensity ) { + theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - Light.call( this, color, intensity ); + normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - this.type = 'DirectionalLight'; + } - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - this.target = new Object3D(); + } - this.shadow = new DirectionalLightShadow(); + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same -} + if ( closed === true ) { -DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { + theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); + theta /= segments; - constructor: DirectionalLight, + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - isDirectionalLight: true, + theta = - theta; - copy: function ( source ) { + } - Light.prototype.copy.call( this, source ); + for ( i = 1; i <= segments; i ++ ) { - this.target = source.target.clone(); + // twist a little... + normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); + binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - this.shadow = source.shadow.clone(); + } - return this; + } - } + return { + tangents: tangents, + normals: normals, + binormals: binormals + }; -} ); + }, -/** - * @author mrdoob / http://mrdoob.com/ - */ + clone: function () { -function AmbientLight( color, intensity ) { + return new this.constructor().copy( this ); - Light.call( this, color, intensity ); + }, - this.type = 'AmbientLight'; + copy: function ( source ) { - this.castShadow = undefined; + this.arcLengthDivisions = source.arcLengthDivisions; -} + return this; -AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { + }, - constructor: AmbientLight, + toJSON: function () { - isAmbientLight: true + var data = { + metadata: { + version: 4.5, + type: 'Curve', + generator: 'Curve.toJSON' + } + }; -} ); + data.arcLengthDivisions = this.arcLengthDivisions; + data.type = this.type; -/** - * @author abelnation / http://github.com/abelnation - */ + return data; -function RectAreaLight( color, intensity, width, height ) { + }, - Light.call( this, color, intensity ); + fromJSON: function ( json ) { - this.type = 'RectAreaLight'; + this.arcLengthDivisions = json.arcLengthDivisions; - this.position.set( 0, 1, 0 ); - this.updateMatrix(); + return this; - this.width = ( width !== undefined ) ? width : 10; - this.height = ( height !== undefined ) ? height : 10; + } - // TODO (abelnation): distance/decay +} ); - // TODO (abelnation): update method for RectAreaLight to update transform to lookat target +function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - // TODO (abelnation): shadows + Curve.call( this ); + + this.type = 'EllipseCurve'; + + this.aX = aX || 0; + this.aY = aY || 0; + + this.xRadius = xRadius || 1; + this.yRadius = yRadius || 1; + + this.aStartAngle = aStartAngle || 0; + this.aEndAngle = aEndAngle || 2 * Math.PI; + + this.aClockwise = aClockwise || false; + + this.aRotation = aRotation || 0; } -// TODO (abelnation): RectAreaLight update when light shape is changed -RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { +EllipseCurve.prototype = Object.create( Curve.prototype ); +EllipseCurve.prototype.constructor = EllipseCurve; - constructor: RectAreaLight, +EllipseCurve.prototype.isEllipseCurve = true; - isRectAreaLight: true, +EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) { - copy: function ( source ) { + var point = optionalTarget || new Vector2(); - Light.prototype.copy.call( this, source ); + var twoPi = Math.PI * 2; + var deltaAngle = this.aEndAngle - this.aStartAngle; + var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - this.width = source.width; - this.height = source.height; + // ensures that deltaAngle is 0 .. 2 PI + while ( deltaAngle < 0 ) deltaAngle += twoPi; + while ( deltaAngle > twoPi ) deltaAngle -= twoPi; - return this; + if ( deltaAngle < Number.EPSILON ) { - }, + if ( samePoints ) { - toJSON: function ( meta ) { + deltaAngle = 0; - var data = Light.prototype.toJSON.call( this, meta ); + } else { - data.object.width = this.width; - data.object.height = this.height; + deltaAngle = twoPi; - return data; + } } -} ); + if ( this.aClockwise === true && ! samePoints ) { -/** - * - * A Track that interpolates Strings - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + if ( deltaAngle === twoPi ) { -function StringKeyframeTrack( name, times, values, interpolation ) { + deltaAngle = - twoPi; - KeyframeTrack.call( this, name, times, values, interpolation ); + } else { -} + deltaAngle = deltaAngle - twoPi; -StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + } - constructor: StringKeyframeTrack, + } - ValueTypeName: 'string', - ValueBufferType: Array, + var angle = this.aStartAngle + t * deltaAngle; + var x = this.aX + this.xRadius * Math.cos( angle ); + var y = this.aY + this.yRadius * Math.sin( angle ); - DefaultInterpolation: InterpolateDiscrete, + if ( this.aRotation !== 0 ) { - InterpolantFactoryMethodLinear: undefined, + var cos = Math.cos( this.aRotation ); + var sin = Math.sin( this.aRotation ); - InterpolantFactoryMethodSmooth: undefined + var tx = x - this.aX; + var ty = y - this.aY; -} ); + // Rotate the point about the center of the ellipse. + x = tx * cos - ty * sin + this.aX; + y = tx * sin + ty * cos + this.aY; -/** - * - * A Track of Boolean keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + } -function BooleanKeyframeTrack( name, times, values ) { + return point.set( x, y ); - KeyframeTrack.call( this, name, times, values ); +}; -} +EllipseCurve.prototype.copy = function ( source ) { -BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + Curve.prototype.copy.call( this, source ); - constructor: BooleanKeyframeTrack, + this.aX = source.aX; + this.aY = source.aY; - ValueTypeName: 'bool', - ValueBufferType: Array, + this.xRadius = source.xRadius; + this.yRadius = source.yRadius; - DefaultInterpolation: InterpolateDiscrete, + this.aStartAngle = source.aStartAngle; + this.aEndAngle = source.aEndAngle; - InterpolantFactoryMethodLinear: undefined, - InterpolantFactoryMethodSmooth: undefined + this.aClockwise = source.aClockwise; - // Note: Actually this track could have a optimized / compressed - // representation of a single value and a custom interpolant that - // computes "firstValue ^ isOdd( index )". + this.aRotation = source.aRotation; -} ); + return this; -/** - * Abstract base class of interpolants over parametric samples. - * - * The parameter domain is one dimensional, typically the time or a path - * along a curve defined by the data. - * - * The sample values can have any dimensionality and derived classes may - * apply special interpretations to the data. - * - * This class provides the interval seek in a Template Method, deferring - * the actual interpolation to derived classes. - * - * Time complexity is O(1) for linear access crossing at most two points - * and O(log N) for random access, where N is the number of positions. - * - * References: - * - * http://www.oodesign.com/template-method-pattern.html - * - * @author tschw - */ +}; -function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; +EllipseCurve.prototype.toJSON = function () { - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; + var data = Curve.prototype.toJSON.call( this ); -} + data.aX = this.aX; + data.aY = this.aY; -Object.assign( Interpolant.prototype, { + data.xRadius = this.xRadius; + data.yRadius = this.yRadius; - evaluate: function ( t ) { + data.aStartAngle = this.aStartAngle; + data.aEndAngle = this.aEndAngle; - var pp = this.parameterPositions, - i1 = this._cachedIndex, + data.aClockwise = this.aClockwise; - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; + data.aRotation = this.aRotation; - validate_interval: { + return data; - seek: { +}; - var right; +EllipseCurve.prototype.fromJSON = function ( json ) { - linear_scan: { + Curve.prototype.fromJSON.call( this, json ); - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { + this.aX = json.aX; + this.aY = json.aY; - for ( var giveUpAt = i1 + 2; ; ) { + this.xRadius = json.xRadius; + this.yRadius = json.yRadius; - if ( t1 === undefined ) { + this.aStartAngle = json.aStartAngle; + this.aEndAngle = json.aEndAngle; - if ( t < t0 ) break forward_scan; + this.aClockwise = json.aClockwise; - // after end + this.aRotation = json.aRotation; - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t, t0 ); + return this; - } +}; - if ( i1 === giveUpAt ) break; // this loop +function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - t0 = t1; - t1 = pp[ ++ i1 ]; + EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - if ( t < t1 ) { + this.type = 'ArcCurve'; - // we have arrived at the sought interval - break seek; +} - } +ArcCurve.prototype = Object.create( EllipseCurve.prototype ); +ArcCurve.prototype.constructor = ArcCurve; - } +ArcCurve.prototype.isArcCurve = true; - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; +/** + * @author zz85 https://github.com/zz85 + * + * Centripetal CatmullRom Curve - which is useful for avoiding + * cusps and self-intersections in non-uniform catmull rom curves. + * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + * + * curve.type accepts centripetal(default), chordal and catmullrom + * curve.tension is used for catmullrom which defaults to 0.5 + */ - } - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { +/* +Based on an optimized c++ solution in + - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ + - http://ideone.com/NoEbVM - // looping? +This CubicPoly class could be used for reusing some variables and calculations, +but for three.js curve use, it could be possible inlined and flatten into a single function call +which can be placed in CurveUtils. +*/ - var t1global = pp[ 1 ]; +function CubicPoly() { - if ( t < t1global ) { + var c0 = 0, c1 = 0, c2 = 0, c3 = 0; - i1 = 2; // + 1, using the scan for the details - t0 = t1global; + /* + * Compute coefficients for a cubic polynomial + * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 + * such that + * p(0) = x0, p(1) = x1 + * and + * p'(0) = t0, p'(1) = t1. + */ + function init( x0, x1, t0, t1 ) { - } + c0 = x0; + c1 = t0; + c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; + c3 = 2 * x0 - 2 * x1 + t0 + t1; - // linear reverse scan + } - for ( var giveUpAt = i1 - 2; ; ) { + return { - if ( t0 === undefined ) { + initCatmullRom: function ( x0, x1, x2, x3, tension ) { - // before start + init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); + }, - } + initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - if ( i1 === giveUpAt ) break; // this loop + // compute tangents when parameterized in [t1,t2] + var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; + var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - t1 = t0; - t0 = pp[ -- i1 - 1 ]; + // rescale tangents for parametrization in [0,1] + t1 *= dt1; + t2 *= dt1; - if ( t >= t0 ) { + init( x1, x2, t1, t2 ); - // we have arrived at the sought interval - break seek; + }, - } + calc: function ( t ) { - } + var t2 = t * t; + var t3 = t2 * t; + return c0 + c1 * t + c2 * t2 + c3 * t3; - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; + } - } + }; - // the interval is valid +} - break validate_interval; +// - } // linear scan +var tmp = new Vector3(); +var px = new CubicPoly(); +var py = new CubicPoly(); +var pz = new CubicPoly(); - // binary search +function CatmullRomCurve3( points, closed, curveType, tension ) { - while ( i1 < right ) { + Curve.call( this ); - var mid = ( i1 + right ) >>> 1; + this.type = 'CatmullRomCurve3'; - if ( t < pp[ mid ] ) { + this.points = points || []; + this.closed = closed || false; + this.curveType = curveType || 'centripetal'; + this.tension = tension || 0.5; - right = mid; +} - } else { +CatmullRomCurve3.prototype = Object.create( Curve.prototype ); +CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; - i1 = mid + 1; +CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; - } +CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector3(); - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; + var points = this.points; + var l = points.length; - // check boundary cases, again + var p = ( l - ( this.closed ? 0 : 1 ) ) * t; + var intPoint = Math.floor( p ); + var weight = p - intPoint; - if ( t0 === undefined ) { + if ( this.closed ) { - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - } + } else if ( weight === 0 && intPoint === l - 1 ) { - if ( t1 === undefined ) { + intPoint = l - 2; + weight = 1; - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t0, t ); + } - } + var p0, p1, p2, p3; // 4 points - } // seek + if ( this.closed || intPoint > 0 ) { - this._cachedIndex = i1; + p0 = points[ ( intPoint - 1 ) % l ]; - this.intervalChanged_( i1, t0, t1 ); + } else { - } // validate_interval + // extrapolate first point + tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); + p0 = tmp; - return this.interpolate_( i1, t0, t, t1 ); + } - }, + p1 = points[ intPoint % l ]; + p2 = points[ ( intPoint + 1 ) % l ]; - settings: null, // optional, subclass-specific settings structure - // Note: The indirection allows central control of many interpolants. + if ( this.closed || intPoint + 2 < l ) { - // --- Protected interface + p3 = points[ ( intPoint + 2 ) % l ]; - DefaultSettings_: {}, + } else { - getSettings_: function () { + // extrapolate last point + tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); + p3 = tmp; - return this.settings || this.DefaultSettings_; + } - }, + if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - copySampleValue_: function ( index ) { + // init Centripetal / Chordal Catmull-Rom + var pow = this.curveType === 'chordal' ? 0.5 : 0.25; + var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); + var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); + var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - // copies a sample value to the result buffer + // safety check for repeated points + if ( dt1 < 1e-4 ) dt1 = 1.0; + if ( dt0 < 1e-4 ) dt0 = dt1; + if ( dt2 < 1e-4 ) dt2 = dt1; - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; + px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); + py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); + pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - for ( var i = 0; i !== stride; ++ i ) { + } else if ( this.curveType === 'catmullrom' ) { - result[ i ] = values[ offset + i ]; + px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); + py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); + pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); - } + } - return result; + point.set( + px.calc( weight ), + py.calc( weight ), + pz.calc( weight ) + ); - }, + return point; - // Template methods for derived classes: +}; - interpolate_: function ( /* i1, t0, t, t1 */ ) { +CatmullRomCurve3.prototype.copy = function ( source ) { - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer + Curve.prototype.copy.call( this, source ); - }, + this.points = []; - intervalChanged_: function ( /* i1, t0, t1 */ ) { + for ( var i = 0, l = source.points.length; i < l; i ++ ) { - // empty + var point = source.points[ i ]; + + this.points.push( point.clone() ); } -} ); + this.closed = source.closed; + this.curveType = source.curveType; + this.tension = source.tension; -//!\ DECLARE ALIAS AFTER assign prototype ! -Object.assign( Interpolant.prototype, { + return this; - //( 0, t, t0 ), returns this.resultBuffer - beforeStart_: Interpolant.prototype.copySampleValue_, +}; - //( N-1, tN-1, t ), returns this.resultBuffer - afterEnd_: Interpolant.prototype.copySampleValue_, +CatmullRomCurve3.prototype.toJSON = function () { -} ); + var data = Curve.prototype.toJSON.call( this ); -/** - * Spherical linear unit quaternion interpolant. - * - * @author tschw - */ + data.points = []; -function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + for ( var i = 0, l = this.points.length; i < l; i ++ ) { - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + var point = this.points[ i ]; + data.points.push( point.toArray() ); -} + } -QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + data.closed = this.closed; + data.curveType = this.curveType; + data.tension = this.tension; - constructor: QuaternionLinearInterpolant, + return data; - interpolate_: function ( i1, t0, t, t1 ) { +}; - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, +CatmullRomCurve3.prototype.fromJSON = function ( json ) { - offset = i1 * stride, + Curve.prototype.fromJSON.call( this, json ); - alpha = ( t - t0 ) / ( t1 - t0 ); + this.points = []; - for ( var end = offset + stride; offset !== end; offset += 4 ) { + for ( var i = 0, l = json.points.length; i < l; i ++ ) { - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); + var point = json.points[ i ]; + this.points.push( new Vector3().fromArray( point ) ); - } + } - return result; + this.closed = json.closed; + this.curveType = json.curveType; + this.tension = json.tension; - } + return this; -} ); +}; /** + * @author zz85 / http://www.lab4games.net/zz85/blog * - * A Track of quaternion keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw + * Bezier Curves formulas obtained from + * http://en.wikipedia.org/wiki/Bézier_curve */ -function QuaternionKeyframeTrack( name, times, values, interpolation ) { +function CatmullRom( t, p0, p1, p2, p3 ) { - KeyframeTrack.call( this, name, times, values, interpolation ); + var v0 = ( p2 - p0 ) * 0.5; + var v1 = ( p3 - p1 ) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; } -QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { +// - constructor: QuaternionKeyframeTrack, +function QuadraticBezierP0( t, p ) { - ValueTypeName: 'quaternion', + var k = 1 - t; + return k * k * p; - // ValueBufferType is inherited +} - DefaultInterpolation: InterpolateLinear, +function QuadraticBezierP1( t, p ) { - InterpolantFactoryMethodLinear: function ( result ) { + return 2 * ( 1 - t ) * t * p; - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); +} - }, +function QuadraticBezierP2( t, p ) { - InterpolantFactoryMethodSmooth: undefined // not yet implemented + return t * t * p; -} ); +} -/** - * - * A Track of keyframe values that represent color. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function ColorKeyframeTrack( name, times, values, interpolation ) { +function QuadraticBezier( t, p0, p1, p2 ) { - KeyframeTrack.call( this, name, times, values, interpolation ); + return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + + QuadraticBezierP2( t, p2 ); } -ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - - constructor: ColorKeyframeTrack, +// - ValueTypeName: 'color' +function CubicBezierP0( t, p ) { - // ValueBufferType is inherited + var k = 1 - t; + return k * k * k * p; - // DefaultInterpolation is inherited +} - // Note: Very basic implementation and nothing special yet. - // However, this is the place for color space parameterization. +function CubicBezierP1( t, p ) { -} ); + var k = 1 - t; + return 3 * k * k * t * p; -/** - * - * A Track of numeric keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ +} -function NumberKeyframeTrack( name, times, values, interpolation ) { +function CubicBezierP2( t, p ) { - KeyframeTrack.call( this, name, times, values, interpolation ); + return 3 * ( 1 - t ) * t * t * p; } -NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { +function CubicBezierP3( t, p ) { - constructor: NumberKeyframeTrack, + return t * t * t * p; - ValueTypeName: 'number' +} - // ValueBufferType is inherited +function CubicBezier( t, p0, p1, p2, p3 ) { - // DefaultInterpolation is inherited + return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + + CubicBezierP3( t, p3 ); -} ); +} -/** - * Fast and simple cubic spline interpolant. - * - * It was derived from a Hermitian construction setting the first derivative - * at each sample position to the linear slope between neighboring positions - * over their parameter interval. - * - * @author tschw - */ +function CubicBezierCurve( v0, v1, v2, v3 ) { -function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + Curve.call( this ); - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + this.type = 'CubicBezierCurve'; - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; + this.v0 = v0 || new Vector2(); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); + this.v3 = v3 || new Vector2(); } -CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { +CubicBezierCurve.prototype = Object.create( Curve.prototype ); +CubicBezierCurve.prototype.constructor = CubicBezierCurve; - constructor: CubicInterpolant, +CubicBezierCurve.prototype.isCubicBezierCurve = true; - DefaultSettings_: { +CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding + var point = optionalTarget || new Vector2(); - }, + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - intervalChanged_: function ( i1, t0, t1 ) { + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) + ); - var pp = this.parameterPositions, - iPrev = i1 - 2, - iNext = i1 + 1, + return point; - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; +}; - if ( tPrev === undefined ) { +CubicBezierCurve.prototype.copy = function ( source ) { - switch ( this.getSettings_().endingStart ) { + Curve.prototype.copy.call( this, source ); - case ZeroSlopeEnding: + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; + return this; - break; +}; - case WrapAroundEnding: +CubicBezierCurve.prototype.toJSON = function () { - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + var data = Curve.prototype.toJSON.call( this ); - break; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - default: // ZeroCurvatureEnding + return data; - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; +}; - } +CubicBezierCurve.prototype.fromJSON = function ( json ) { - } + Curve.prototype.fromJSON.call( this, json ); - if ( tNext === undefined ) { + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); - switch ( this.getSettings_().endingEnd ) { + return this; - case ZeroSlopeEnding: +}; - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; +function CubicBezierCurve3( v0, v1, v2, v3 ) { - break; + Curve.call( this ); - case WrapAroundEnding: + this.type = 'CubicBezierCurve3'; - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; + this.v0 = v0 || new Vector3(); + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); + this.v3 = v3 || new Vector3(); - break; +} - default: // ZeroCurvatureEnding +CubicBezierCurve3.prototype = Object.create( Curve.prototype ); +CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; +CubicBezierCurve3.prototype.isCubicBezierCurve3 = true; - } +CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector3(); - var halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), + CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) + ); - }, + return point; - interpolate_: function ( i1, t0, t, t1 ) { +}; - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, +CubicBezierCurve3.prototype.copy = function ( source ) { - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, + Curve.prototype.copy.call( this, source ); - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - // evaluate polynomials + return this; - var sP = - wP * ppp + 2 * wP * pp - wP * p; - var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - var sN = wN * ppp - wN * pp; +}; - // combine data linearly +CubicBezierCurve3.prototype.toJSON = function () { - for ( var i = 0; i !== stride; ++ i ) { + var data = Curve.prototype.toJSON.call( this ); - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - } + return data; - return result; +}; - } +CubicBezierCurve3.prototype.fromJSON = function ( json ) { -} ); + Curve.prototype.fromJSON.call( this, json ); -/** - * @author tschw - */ + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); -function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + return this; - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); +}; -} +function LineCurve( v1, v2 ) { -LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + Curve.call( this ); - constructor: LinearInterpolant, + this.type = 'LineCurve'; - interpolate_: function ( i1, t0, t, t1 ) { + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, +} - offset1 = i1 * stride, - offset0 = offset1 - stride, +LineCurve.prototype = Object.create( Curve.prototype ); +LineCurve.prototype.constructor = LineCurve; - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; +LineCurve.prototype.isLineCurve = true; - for ( var i = 0; i !== stride; ++ i ) { +LineCurve.prototype.getPoint = function ( t, optionalTarget ) { - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; + var point = optionalTarget || new Vector2(); - } + if ( t === 1 ) { - return result; + point.copy( this.v2 ); + + } else { + + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); } -} ); + return point; -/** - * - * Interpolant that evaluates to the sample value at the position preceeding - * the parameter. - * - * @author tschw - */ +}; -function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { +// Line curve is linear, so we can overwrite default getPointAt - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); +LineCurve.prototype.getPointAt = function ( u, optionalTarget ) { -} + return this.getPoint( u, optionalTarget ); -DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { +}; - constructor: DiscreteInterpolant, +LineCurve.prototype.getTangent = function ( /* t */ ) { - interpolate_: function ( i1 /*, t0, t, t1 */ ) { + var tangent = this.v2.clone().sub( this.v1 ); - return this.copySampleValue_( i1 - 1 ); + return tangent.normalize(); - } +}; -} ); +LineCurve.prototype.copy = function ( source ) { -/** - * @author tschw - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ + Curve.prototype.copy.call( this, source ); -var AnimationUtils = { + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - // same as Array.prototype.slice, but also works on typed arrays - arraySlice: function ( array, from, to ) { + return this; - if ( AnimationUtils.isTypedArray( array ) ) { +}; - // in ios9 array.subarray(from, undefined) will return empty array - // but array.subarray(from) or array.subarray(from, len) is correct - return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) ); +LineCurve.prototype.toJSON = function () { - } + var data = Curve.prototype.toJSON.call( this ); - return array.slice( from, to ); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - }, + return data; - // converts an array to a specific type - convertArray: function ( array, type, forceClone ) { +}; - if ( ! array || // let 'undefined' and 'null' pass - ! forceClone && array.constructor === type ) return array; +LineCurve.prototype.fromJSON = function ( json ) { - if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + Curve.prototype.fromJSON.call( this, json ); - return new type( array ); // create typed array + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - } + return this; - return Array.prototype.slice.call( array ); // create Array +}; - }, +function LineCurve3( v1, v2 ) { - isTypedArray: function ( object ) { + Curve.call( this ); - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); + this.type = 'LineCurve3'; - }, + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); - // returns an array by which times and values can be sorted - getKeyframeOrder: function ( times ) { +} - function compareTime( i, j ) { +LineCurve3.prototype = Object.create( Curve.prototype ); +LineCurve3.prototype.constructor = LineCurve3; - return times[ i ] - times[ j ]; +LineCurve3.prototype.isLineCurve3 = true; - } +LineCurve3.prototype.getPoint = function ( t, optionalTarget ) { - var n = times.length; - var result = new Array( n ); - for ( var i = 0; i !== n; ++ i ) result[ i ] = i; + var point = optionalTarget || new Vector3(); - result.sort( compareTime ); + if ( t === 1 ) { - return result; + point.copy( this.v2 ); - }, + } else { - // uses the array previously returned by 'getKeyframeOrder' to sort data - sortedArray: function ( values, stride, order ) { + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); - var nValues = values.length; - var result = new values.constructor( nValues ); + } - for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + return point; - var srcOffset = order[ i ] * stride; +}; - for ( var j = 0; j !== stride; ++ j ) { +// Line curve is linear, so we can overwrite default getPointAt - result[ dstOffset ++ ] = values[ srcOffset + j ]; +LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) { - } + return this.getPoint( u, optionalTarget ); - } +}; - return result; +LineCurve3.prototype.copy = function ( source ) { - }, + Curve.prototype.copy.call( this, source ); - // function for parsing AOS keyframe formats - flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - var i = 1, key = jsonKeys[ 0 ]; + return this; - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { +}; - key = jsonKeys[ i ++ ]; +LineCurve3.prototype.toJSON = function () { - } + var data = Curve.prototype.toJSON.call( this ); - if ( key === undefined ) return; // no data + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - var value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data + return data; - if ( Array.isArray( value ) ) { +}; - do { +LineCurve3.prototype.fromJSON = function ( json ) { - value = key[ valuePropertyName ]; + Curve.prototype.fromJSON.call( this, json ); - if ( value !== undefined ) { + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - times.push( key.time ); - values.push.apply( values, value ); // push all elements + return this; - } +}; - key = jsonKeys[ i ++ ]; +function QuadraticBezierCurve( v0, v1, v2 ) { - } while ( key !== undefined ); + Curve.call( this ); - } else if ( value.toArray !== undefined ) { + this.type = 'QuadraticBezierCurve'; - // ...assume THREE.Math-ish + this.v0 = v0 || new Vector2(); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); - do { +} - value = key[ valuePropertyName ]; +QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); +QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; - if ( value !== undefined ) { +QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; - times.push( key.time ); - value.toArray( values, values.length ); +QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector2(); - key = jsonKeys[ i ++ ]; + var v0 = this.v0, v1 = this.v1, v2 = this.v2; - } while ( key !== undefined ); + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ) + ); - } else { + return point; - // otherwise push as-is +}; - do { +QuadraticBezierCurve.prototype.copy = function ( source ) { - value = key[ valuePropertyName ]; + Curve.prototype.copy.call( this, source ); - if ( value !== undefined ) { + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - times.push( key.time ); - values.push( value ); + return this; - } +}; - key = jsonKeys[ i ++ ]; +QuadraticBezierCurve.prototype.toJSON = function () { - } while ( key !== undefined ); + var data = Curve.prototype.toJSON.call( this ); - } + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - } + return data; }; -/** - * - * A timed sequence of keyframes for a specific property. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ +QuadraticBezierCurve.prototype.fromJSON = function ( json ) { -function KeyframeTrack( name, times, values, interpolation ) { + Curve.prototype.fromJSON.call( this, json ); - if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); - if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - this.name = name; + return this; - this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); - this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); +}; - this.setInterpolation( interpolation || this.DefaultInterpolation ); +function QuadraticBezierCurve3( v0, v1, v2 ) { - this.validate(); - this.optimize(); + Curve.call( this ); -} + this.type = 'QuadraticBezierCurve3'; -// Static methods: + this.v0 = v0 || new Vector3(); + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); -Object.assign( KeyframeTrack, { +} - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): +QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); +QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; - parse: function ( json ) { +QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; - if ( json.type === undefined ) { +QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); + var point = optionalTarget || new Vector3(); - } + var v0 = this.v0, v1 = this.v1, v2 = this.v2; - var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type ); + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ), + QuadraticBezier( t, v0.z, v1.z, v2.z ) + ); - if ( json.times === undefined ) { + return point; - var times = [], values = []; +}; - AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); +QuadraticBezierCurve3.prototype.copy = function ( source ) { - json.times = times; - json.values = values; + Curve.prototype.copy.call( this, source ); - } + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { + return this; - return trackType.parse( json ); +}; - } else { +QuadraticBezierCurve3.prototype.toJSON = function () { - // by default, we assume a constructor compatible with the base - return new trackType( json.name, json.times, json.values, json.interpolation ); + var data = Curve.prototype.toJSON.call( this ); - } + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - }, + return data; - toJSON: function ( track ) { +}; - var trackType = track.constructor; +QuadraticBezierCurve3.prototype.fromJSON = function ( json ) { - var json; + Curve.prototype.fromJSON.call( this, json ); - // derived classes can define a static toJSON method - if ( trackType.toJSON !== undefined ) { + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - json = trackType.toJSON( track ); + return this; - } else { +}; - // by default, we assume the data can be serialized as-is - json = { +function SplineCurve( points /* array of Vector2 */ ) { - 'name': track.name, - 'times': AnimationUtils.convertArray( track.times, Array ), - 'values': AnimationUtils.convertArray( track.values, Array ) + Curve.call( this ); - }; + this.type = 'SplineCurve'; - var interpolation = track.getInterpolation(); + this.points = points || []; - if ( interpolation !== track.DefaultInterpolation ) { +} - json.interpolation = interpolation; +SplineCurve.prototype = Object.create( Curve.prototype ); +SplineCurve.prototype.constructor = SplineCurve; - } +SplineCurve.prototype.isSplineCurve = true; - } +SplineCurve.prototype.getPoint = function ( t, optionalTarget ) { - json.type = track.ValueTypeName; // mandatory + var point = optionalTarget || new Vector2(); - return json; + var points = this.points; + var p = ( points.length - 1 ) * t; - }, + var intPoint = Math.floor( p ); + var weight = p - intPoint; - _getTrackTypeForValueTypeName: function ( typeName ) { + var p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; + var p1 = points[ intPoint ]; + var p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; + var p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - switch ( typeName.toLowerCase() ) { + point.set( + CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), + CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) + ); - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': + return point; - return NumberKeyframeTrack; +}; - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': +SplineCurve.prototype.copy = function ( source ) { - return VectorKeyframeTrack; + Curve.prototype.copy.call( this, source ); - case 'color': + this.points = []; - return ColorKeyframeTrack; + for ( var i = 0, l = source.points.length; i < l; i ++ ) { - case 'quaternion': + var point = source.points[ i ]; - return QuaternionKeyframeTrack; + this.points.push( point.clone() ); - case 'bool': - case 'boolean': + } - return BooleanKeyframeTrack; + return this; - case 'string': +}; - return StringKeyframeTrack; +SplineCurve.prototype.toJSON = function () { - } + var data = Curve.prototype.toJSON.call( this ); - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); + data.points = []; + + for ( var i = 0, l = this.points.length; i < l; i ++ ) { + + var point = this.points[ i ]; + data.points.push( point.toArray() ); } -} ); + return data; -Object.assign( KeyframeTrack.prototype, { +}; - constructor: KeyframeTrack, +SplineCurve.prototype.fromJSON = function ( json ) { - TimeBufferType: Float32Array, + Curve.prototype.fromJSON.call( this, json ); - ValueBufferType: Float32Array, + this.points = []; - DefaultInterpolation: InterpolateLinear, + for ( var i = 0, l = json.points.length; i < l; i ++ ) { - InterpolantFactoryMethodDiscrete: function ( result ) { + var point = json.points[ i ]; + this.points.push( new Vector2().fromArray( point ) ); - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); + } - }, + return this; - InterpolantFactoryMethodLinear: function ( result ) { +}; - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); - }, - InterpolantFactoryMethodSmooth: function ( result ) { +var Curves = Object.freeze({ + ArcCurve: ArcCurve, + CatmullRomCurve3: CatmullRomCurve3, + CubicBezierCurve: CubicBezierCurve, + CubicBezierCurve3: CubicBezierCurve3, + EllipseCurve: EllipseCurve, + LineCurve: LineCurve, + LineCurve3: LineCurve3, + QuadraticBezierCurve: QuadraticBezierCurve, + QuadraticBezierCurve3: QuadraticBezierCurve3, + SplineCurve: SplineCurve +}); - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * + **/ - }, +/************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ - setInterpolation: function ( interpolation ) { +function CurvePath() { - var factoryMethod; + Curve.call( this ); - switch ( interpolation ) { + this.type = 'CurvePath'; - case InterpolateDiscrete: + this.curves = []; + this.autoClose = false; // Automatically closes the path - factoryMethod = this.InterpolantFactoryMethodDiscrete; +} - break; +CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { - case InterpolateLinear: + constructor: CurvePath, - factoryMethod = this.InterpolantFactoryMethodLinear; + add: function ( curve ) { - break; + this.curves.push( curve ); - case InterpolateSmooth: + }, - factoryMethod = this.InterpolantFactoryMethodSmooth; + closePath: function () { - break; + // Add a line curve if start and end of lines are not connected + var startPoint = this.curves[ 0 ].getPoint( 0 ); + var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); + + if ( ! startPoint.equals( endPoint ) ) { + + this.curves.push( new LineCurve( endPoint, startPoint ) ); } - if ( factoryMethod === undefined ) { + }, - var message = "unsupported interpolation for " + - this.ValueTypeName + " keyframe track named " + this.name; + // To get accurate point with reference to + // entire path distance at time t, + // following has to be done: - if ( this.createInterpolant === undefined ) { + // 1. Length of each sub path have to be known + // 2. Locate and identify type of curve + // 3. Get t for the curve + // 4. Return curve.getPointAt(t') - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { + getPoint: function ( t ) { - this.setInterpolation( this.DefaultInterpolation ); + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0; - } else { + // To think about boundaries points. - throw new Error( message ); // fatal, in this case + while ( i < curveLengths.length ) { - } + if ( curveLengths[ i ] >= d ) { + + var diff = curveLengths[ i ] - d; + var curve = this.curves[ i ]; + + var segmentLength = curve.getLength(); + var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + + return curve.getPointAt( u ); } - console.warn( 'THREE.KeyframeTrack:', message ); - return; + i ++; } - this.createInterpolant = factoryMethod; + return null; + + // loop where sum != 0, sum > d , sum+1 seconds conversions) - scale: function ( timeScale ) { + getPoints: function ( divisions ) { - if ( timeScale !== 1.0 ) { + divisions = divisions || 12; - var times = this.times; + var points = [], last; - for ( var i = 0, n = times.length; i !== n; ++ i ) { + for ( var i = 0, curves = this.curves; i < curves.length; i ++ ) { - times[ i ] *= timeScale; + var curve = curves[ i ]; + var resolution = ( curve && curve.isEllipseCurve ) ? divisions * 2 + : ( curve && curve.isLineCurve ) ? 1 + : ( curve && curve.isSplineCurve ) ? divisions * curve.points.length + : divisions; - } + var pts = curve.getPoints( resolution ); - } + for ( var j = 0; j < pts.length; j ++ ) { - return this; + var point = pts[ j ]; - }, + if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates - // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. - // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values - trim: function ( startTime, endTime ) { + points.push( point ); + last = point; - var times = this.times, - nKeys = times.length, - from = 0, - to = nKeys - 1; + } - while ( from !== nKeys && times[ from ] < startTime ) { + } - ++ from; + if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { + + points.push( points[ 0 ] ); } - while ( to !== - 1 && times[ to ] > endTime ) { + return points; - -- to; + }, - } + copy: function ( source ) { - ++ to; // inclusive -> exclusive bound + Curve.prototype.copy.call( this, source ); - if ( from !== 0 || to !== nKeys ) { + this.curves = []; - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; + for ( var i = 0, l = source.curves.length; i < l; i ++ ) { - var stride = this.getValueSize(); - this.times = AnimationUtils.arraySlice( times, from, to ); - this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); + var curve = source.curves[ i ]; + + this.curves.push( curve.clone() ); } + this.autoClose = source.autoClose; + return this; }, - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate: function () { + toJSON: function () { - var valid = true; + var data = Curve.prototype.toJSON.call( this ); - var valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { + data.autoClose = this.autoClose; + data.curves = []; - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; + for ( var i = 0, l = this.curves.length; i < l; i ++ ) { + + var curve = this.curves[ i ]; + data.curves.push( curve.toJSON() ); } - var times = this.times, - values = this.values, + return data; - nKeys = times.length; + }, - if ( nKeys === 0 ) { + fromJSON: function ( json ) { - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; + Curve.prototype.fromJSON.call( this, json ); - } + this.autoClose = json.autoClose; + this.curves = []; - var prevTime = null; + for ( var i = 0, l = json.curves.length; i < l; i ++ ) { - for ( var i = 0; i !== nKeys; i ++ ) { + var curve = json.curves[ i ]; + this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); - var currTime = times[ i ]; + } - if ( typeof currTime === 'number' && isNaN( currTime ) ) { + return this; - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; + } - } +} ); - if ( prevTime !== null && prevTime > currTime ) { +/** + * @author zz85 / http://www.lab4games.net/zz85/blog + * Creates free form 2d path using series of points, lines or curves. + **/ - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; +function Path( points ) { - } + CurvePath.call( this ); - prevTime = currTime; + this.type = 'Path'; - } + this.currentPoint = new Vector2(); - if ( values !== undefined ) { + if ( points ) { - if ( AnimationUtils.isTypedArray( values ) ) { + this.setFromPoints( points ); - for ( var i = 0, n = values.length; i !== n; ++ i ) { + } - var value = values[ i ]; +} - if ( isNaN( value ) ) { +Path.prototype = Object.assign( Object.create( CurvePath.prototype ), { - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; + constructor: Path, - } + setFromPoints: function ( points ) { - } + this.moveTo( points[ 0 ].x, points[ 0 ].y ); - } + for ( var i = 1, l = points.length; i < l; i ++ ) { + + this.lineTo( points[ i ].x, points[ i ].y ); } - return valid; + }, + + moveTo: function ( x, y ) { + + this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? }, - // removes equivalent sequential keys as common in morph target sequences - // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) - optimize: function () { + lineTo: function ( x, y ) { - var times = this.times, - values = this.values, - stride = this.getValueSize(), + var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); + this.curves.push( curve ); - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, + this.currentPoint.set( x, y ); - writeIndex = 1, - lastIndex = times.length - 1; + }, - for ( var i = 1; i < lastIndex; ++ i ) { + quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { - var keep = false; + var curve = new QuadraticBezierCurve( + this.currentPoint.clone(), + new Vector2( aCPx, aCPy ), + new Vector2( aX, aY ) + ); - var time = times[ i ]; - var timeNext = times[ i + 1 ]; + this.curves.push( curve ); - // remove adjacent keyframes scheduled at the same time + this.currentPoint.set( aX, aY ); - if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { + }, - if ( ! smoothInterpolation ) { + bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - // remove unnecessary keyframes same as their neighbors + var curve = new CubicBezierCurve( + this.currentPoint.clone(), + new Vector2( aCP1x, aCP1y ), + new Vector2( aCP2x, aCP2y ), + new Vector2( aX, aY ) + ); - var offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; + this.curves.push( curve ); - for ( var j = 0; j !== stride; ++ j ) { + this.currentPoint.set( aX, aY ); - var value = values[ offset + j ]; + }, - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { + splineThru: function ( pts /*Array of Vector*/ ) { - keep = true; - break; + var npts = [ this.currentPoint.clone() ].concat( pts ); - } + var curve = new SplineCurve( npts ); + this.curves.push( curve ); - } + this.currentPoint.copy( pts[ pts.length - 1 ] ); - } else { + }, - keep = true; + arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - } + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; - } + this.absarc( aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); - // in-place compaction + }, - if ( keep ) { + absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - if ( i !== writeIndex ) { + this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - times[ writeIndex ] = times[ i ]; + }, - var readOffset = i * stride, - writeOffset = writeIndex * stride; + ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - for ( var j = 0; j !== stride; ++ j ) { + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; - values[ writeOffset + j ] = values[ readOffset + j ]; + this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - } + }, - } + absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - ++ writeIndex; + var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + + if ( this.curves.length > 0 ) { + + // if a previous curve is present, attempt to join + var firstPoint = curve.getPoint( 0 ); + + if ( ! firstPoint.equals( this.currentPoint ) ) { + + this.lineTo( firstPoint.x, firstPoint.y ); } } - // flush last keyframe (compaction looks ahead) + this.curves.push( curve ); - if ( lastIndex > 0 ) { + var lastPoint = curve.getPoint( 1 ); + this.currentPoint.copy( lastPoint ); - times[ writeIndex ] = times[ lastIndex ]; + }, - for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { + copy: function ( source ) { - values[ writeOffset + j ] = values[ readOffset + j ]; + CurvePath.prototype.copy.call( this, source ); - } + this.currentPoint.copy( source.currentPoint ); - ++ writeIndex; + return this; - } + }, - if ( writeIndex !== times.length ) { + toJSON: function () { - this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); - this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); + var data = CurvePath.prototype.toJSON.call( this ); - } + data.currentPoint = this.currentPoint.toArray(); - return this; + return data; - } + }, -} ); + fromJSON: function ( json ) { -/** - * - * A Track of vectored keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - -function VectorKeyframeTrack( name, times, values, interpolation ) { - - KeyframeTrack.call( this, name, times, values, interpolation ); - -} - -VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + CurvePath.prototype.fromJSON.call( this, json ); - constructor: VectorKeyframeTrack, - - ValueTypeName: 'vector' + this.currentPoint.fromArray( json.currentPoint ); - // ValueBufferType is inherited + return this; - // DefaultInterpolation is inherited + } } ); /** - * - * Reusable set of Tracks that represent an animation. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ - -function AnimationClip( name, duration, tracks ) { + * @author zz85 / http://www.lab4games.net/zz85/blog + * Defines a 2d shape plane using paths. + **/ - this.name = name; - this.tracks = tracks; - this.duration = ( duration !== undefined ) ? duration : - 1; +// STEP 1 Create a path. +// STEP 2 Turn path into shape. +// STEP 3 ExtrudeGeometry takes in Shape/Shapes +// STEP 3a - Extract points from each shape, turn to vertices +// STEP 3b - Triangulate each shape, add faces. - this.uuid = _Math.generateUUID(); +function Shape( points ) { - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { + Path.call( this, points ); - this.resetDuration(); + this.uuid = _Math.generateUUID(); - } + this.type = 'Shape'; - this.optimize(); + this.holes = []; } -Object.assign( AnimationClip, { +Shape.prototype = Object.assign( Object.create( Path.prototype ), { - parse: function ( json ) { + constructor: Shape, - var tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); + getPointsHoles: function ( divisions ) { - for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { + var holesPts = []; - tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) ); + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + + holesPts[ i ] = this.holes[ i ].getPoints( divisions ); } - return new AnimationClip( json.name, json.duration, tracks ); + return holesPts; }, - toJSON: function ( clip ) { + // get points of shape and holes (keypoints based on segments parameter) - var tracks = [], - clipTracks = clip.tracks; + extractPoints: function ( divisions ) { - var json = { + return { - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks + shape: this.getPoints( divisions ), + holes: this.getPointsHoles( divisions ) }; - for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { - - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); + }, - } + copy: function ( source ) { - return json; + Path.prototype.copy.call( this, source ); - }, + this.holes = []; - CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { + for ( var i = 0, l = source.holes.length; i < l; i ++ ) { - var numMorphTargets = morphTargetSequence.length; - var tracks = []; + var hole = source.holes[ i ]; - for ( var i = 0; i < numMorphTargets; i ++ ) { + this.holes.push( hole.clone() ); - var times = []; - var values = []; + } - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); + return this; - values.push( 0, 1, 0 ); + }, - var order = AnimationUtils.getKeyframeOrder( times ); - times = AnimationUtils.sortedArray( times, 1, order ); - values = AnimationUtils.sortedArray( values, 1, order ); + toJSON: function () { - // if there is a key at the first frame, duplicate it as the - // last frame as well for perfect loop. - if ( ! noLoop && times[ 0 ] === 0 ) { + var data = Path.prototype.toJSON.call( this ); - times.push( numMorphTargets ); - values.push( values[ 0 ] ); + data.uuid = this.uuid; + data.holes = []; - } + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); + var hole = this.holes[ i ]; + data.holes.push( hole.toJSON() ); } - return new AnimationClip( name, - 1, tracks ); + return data; }, - findByName: function ( objectOrClipArray, name ) { + fromJSON: function ( json ) { - var clipArray = objectOrClipArray; + Path.prototype.fromJSON.call( this, json ); - if ( ! Array.isArray( objectOrClipArray ) ) { + this.uuid = json.uuid; + this.holes = []; - var o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; + for ( var i = 0, l = json.holes.length; i < l; i ++ ) { + + var hole = json.holes[ i ]; + this.holes.push( new Path().fromJSON( hole ) ); } - for ( var i = 0; i < clipArray.length; i ++ ) { + return this; - if ( clipArray[ i ].name === name ) { + } - return clipArray[ i ]; +} ); - } +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - } +function Light( color, intensity ) { - return null; + Object3D.call( this ); - }, + this.type = 'Light'; - CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { + this.color = new Color( color ); + this.intensity = intensity !== undefined ? intensity : 1; - var animationToMorphTargets = {}; + this.receiveShadow = undefined; - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - var pattern = /^([\w-]*?)([\d]+)$/; +} - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { +Light.prototype = Object.assign( Object.create( Object3D.prototype ), { - var morphTarget = morphTargets[ i ]; - var parts = morphTarget.name.match( pattern ); + constructor: Light, - if ( parts && parts.length > 1 ) { + isLight: true, - var name = parts[ 1 ]; + copy: function ( source ) { - var animationMorphTargets = animationToMorphTargets[ name ]; - if ( ! animationMorphTargets ) { + Object3D.prototype.copy.call( this, source ); - animationToMorphTargets[ name ] = animationMorphTargets = []; + this.color.copy( source.color ); + this.intensity = source.intensity; - } + return this; - animationMorphTargets.push( morphTarget ); + }, - } + toJSON: function ( meta ) { - } + var data = Object3D.prototype.toJSON.call( this, meta ); - var clips = []; + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; - for ( var name in animationToMorphTargets ) { + if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); - clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); + if ( this.distance !== undefined ) data.object.distance = this.distance; + if ( this.angle !== undefined ) data.object.angle = this.angle; + if ( this.decay !== undefined ) data.object.decay = this.decay; + if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; - } + if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); - return clips; + return data; - }, + } - // parse the animation.hierarchy format - parseAnimation: function ( animation, bones ) { +} ); - if ( ! animation ) { +/** + * @author alteredq / http://alteredqualia.com/ + */ - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; +function HemisphereLight( skyColor, groundColor, intensity ) { - } + Light.call( this, skyColor, intensity ); - var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { + this.type = 'HemisphereLight'; - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { + this.castShadow = undefined; - var times = []; - var values = []; + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); + this.groundColor = new Color( groundColor ); - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { +} - destTracks.push( new trackType( trackName, times, values ) ); +HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { - } + constructor: HemisphereLight, - } + isHemisphereLight: true, - }; + copy: function ( source ) { - var tracks = []; + Light.prototype.copy.call( this, source ); - var clipName = animation.name || 'default'; - // automatic length determination in AnimationClip. - var duration = animation.length || - 1; - var fps = animation.fps || 30; + this.groundColor.copy( source.groundColor ); - var hierarchyTracks = animation.hierarchy || []; + return this; - for ( var h = 0; h < hierarchyTracks.length; h ++ ) { + } - var animationKeys = hierarchyTracks[ h ].keys; +} ); - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; +/** + * @author mrdoob / http://mrdoob.com/ + */ - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { +function LightShadow( camera ) { - // figure out all morph targets used in this track - var morphTargetNames = {}; + this.camera = camera; - for ( var k = 0; k < animationKeys.length; k ++ ) { + this.bias = 0; + this.radius = 1; - if ( animationKeys[ k ].morphTargets ) { + this.mapSize = new Vector2( 512, 512 ); - for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { + this.map = null; + this.matrix = new Matrix4(); - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; +} - } +Object.assign( LightShadow.prototype, { - } + copy: function ( source ) { - } + this.camera = source.camera.clone(); - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( var morphTargetName in morphTargetNames ) { + this.bias = source.bias; + this.radius = source.radius; - var times = []; - var values = []; + this.mapSize.copy( source.mapSize ); - for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { + return this; - var animationKey = animationKeys[ k ]; + }, - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); + clone: function () { - } + return new this.constructor().copy( this ); - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); + }, - } + toJSON: function () { - duration = morphTargetNames.length * ( fps || 1.0 ); + var object = {}; - } else { + if ( this.bias !== 0 ) object.bias = this.bias; + if ( this.radius !== 1 ) object.radius = this.radius; + if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); - // ...assume skeletal animation + object.camera = this.camera.toJSON( false ).object; + delete object.camera.matrix; - var boneName = '.bones[' + bones[ h ].name + ']'; + return object; - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); + } - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); +} ); - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - } +function SpotLightShadow() { - } + LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - if ( tracks.length === 0 ) { +} - return null; +SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - } + constructor: SpotLightShadow, - var clip = new AnimationClip( clipName, duration, tracks ); + isSpotLightShadow: true, - return clip; + update: function ( light ) { + + var camera = this.camera; + + var fov = _Math.RAD2DEG * 2 * light.angle; + var aspect = this.mapSize.width / this.mapSize.height; + var far = light.distance || camera.far; + + if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + + camera.fov = fov; + camera.aspect = aspect; + camera.far = far; + camera.updateProjectionMatrix(); + + } } } ); -Object.assign( AnimationClip.prototype, { +/** + * @author alteredq / http://alteredqualia.com/ + */ - resetDuration: function () { +function SpotLight( color, intensity, distance, angle, penumbra, decay ) { - var tracks = this.tracks, duration = 0; + Light.call( this, color, intensity ); - for ( var i = 0, n = tracks.length; i !== n; ++ i ) { + this.type = 'SpotLight'; - var track = this.tracks[ i ]; + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); + this.target = new Object3D(); - } + Object.defineProperty( this, 'power', { + get: function () { - this.duration = duration; + // intensity = power per solid angle. + // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + return this.intensity * Math.PI; - }, + }, + set: function ( power ) { - trim: function () { + // intensity = power per solid angle. + // ref: equation (17) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + this.intensity = power / Math.PI; - for ( var i = 0; i < this.tracks.length; i ++ ) { + } + } ); - this.tracks[ i ].trim( 0, this.duration ); + this.distance = ( distance !== undefined ) ? distance : 0; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; + this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - } + this.shadow = new SpotLightShadow(); - return this; +} - }, +SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { - optimize: function () { + constructor: SpotLight, - for ( var i = 0; i < this.tracks.length; i ++ ) { + isSpotLight: true, - this.tracks[ i ].optimize(); + copy: function ( source ) { - } + Light.prototype.copy.call( this, source ); + + this.distance = source.distance; + this.angle = source.angle; + this.penumbra = source.penumbra; + this.decay = source.decay; + + this.target = source.target.clone(); + + this.shadow = source.shadow.clone(); return this; @@ -33469,3322 +33625,4046 @@ Object.assign( AnimationClip.prototype, { * @author mrdoob / http://mrdoob.com/ */ -function MaterialLoader( manager ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.textures = {}; +function PointLight( color, intensity, distance, decay ) { -} + Light.call( this, color, intensity ); -Object.assign( MaterialLoader.prototype, { + this.type = 'PointLight'; - load: function ( url, onLoad, onProgress, onError ) { + Object.defineProperty( this, 'power', { + get: function () { - var scope = this; + // intensity = power per solid angle. + // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + return this.intensity * 4 * Math.PI; - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + }, + set: function ( power ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + // intensity = power per solid angle. + // ref: equation (15) from http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + this.intensity = power / ( 4 * Math.PI ); - }, onProgress, onError ); + } + } ); - }, + this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - setTextures: function ( value ) { + this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - this.textures = value; +} - }, +PointLight.prototype = Object.assign( Object.create( Light.prototype ), { - parse: function ( json ) { + constructor: PointLight, - var textures = this.textures; + isPointLight: true, - function getTexture( name ) { + copy: function ( source ) { - if ( textures[ name ] === undefined ) { + Light.prototype.copy.call( this, source ); - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + this.distance = source.distance; + this.decay = source.decay; - } + this.shadow = source.shadow.clone(); - return textures[ name ]; + return this; - } + } - var material = new Materials[ json.type ](); +} ); - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; - if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; - if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.side !== undefined ) material.side = json.side; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; +/** + * @author mrdoob / http://mrdoob.com/ + */ - if ( json.rotation !== undefined ) material.rotation = json.rotation; +function DirectionalLightShadow( ) { - if ( json.linewidth !== 1 ) material.linewidth = json.linewidth; - if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; - if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; - if ( json.scale !== undefined ) material.scale = json.scale; + LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - if ( json.skinning !== undefined ) material.skinning = json.skinning; - if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; - if ( json.dithering !== undefined ) material.dithering = json.dithering; +} - if ( json.visible !== undefined ) material.visible = json.visible; - if ( json.userData !== undefined ) material.userData = json.userData; +DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - // Deprecated + constructor: DirectionalLightShadow - if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading +} ); - // for PointsMaterial +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; +function DirectionalLight( color, intensity ) { - // maps + Light.call( this, color, intensity ); - if ( json.map !== undefined ) material.map = getTexture( json.map ); + this.type = 'DirectionalLight'; - if ( json.alphaMap !== undefined ) { + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - material.alphaMap = getTexture( json.alphaMap ); - material.transparent = true; + this.target = new Object3D(); - } + this.shadow = new DirectionalLightShadow(); - if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); - if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; +} - if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); - if ( json.normalScale !== undefined ) { +DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { - var normalScale = json.normalScale; + constructor: DirectionalLight, - if ( Array.isArray( normalScale ) === false ) { + isDirectionalLight: true, - // Blender exporter used to export a scalar. See #7459 + copy: function ( source ) { - normalScale = [ normalScale, normalScale ]; + Light.prototype.copy.call( this, source ); - } + this.target = source.target.clone(); - material.normalScale = new Vector2().fromArray( normalScale ); + this.shadow = source.shadow.clone(); - } + return this; - if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); - if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; - if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; + } - if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); - if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); +} ); - if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); - if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; +/** + * @author mrdoob / http://mrdoob.com/ + */ - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); +function AmbientLight( color, intensity ) { - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); + Light.call( this, color, intensity ); - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; + this.type = 'AmbientLight'; - if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); - if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; + this.castShadow = undefined; - if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); - if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; +} - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); +AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { - return material; + constructor: AmbientLight, + + isAmbientLight: true + +} ); + +/** + * @author abelnation / http://github.com/abelnation + */ + +function RectAreaLight( color, intensity, width, height ) { + + Light.call( this, color, intensity ); + + this.type = 'RectAreaLight'; + + this.position.set( 0, 1, 0 ); + this.updateMatrix(); + + this.width = ( width !== undefined ) ? width : 10; + this.height = ( height !== undefined ) ? height : 10; + + // TODO (abelnation): distance/decay + + // TODO (abelnation): update method for RectAreaLight to update transform to lookat target + + // TODO (abelnation): shadows + +} + +// TODO (abelnation): RectAreaLight update when light shape is changed +RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { + + constructor: RectAreaLight, + + isRectAreaLight: true, + + copy: function ( source ) { + + Light.prototype.copy.call( this, source ); + + this.width = source.width; + this.height = source.height; + + return this; + + }, + + toJSON: function ( meta ) { + + var data = Light.prototype.toJSON.call( this, meta ); + + data.object.width = this.width; + data.object.height = this.height; + + return data; } } ); /** - * @author mrdoob / http://mrdoob.com/ + * + * A Track that interpolates Strings + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw */ -function BufferGeometryLoader( manager ) { +function StringKeyframeTrack( name, times, values, interpolation ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + KeyframeTrack.call( this, name, times, values, interpolation ); } -Object.assign( BufferGeometryLoader.prototype, { +StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - load: function ( url, onLoad, onProgress, onError ) { + constructor: StringKeyframeTrack, - var scope = this; + ValueTypeName: 'string', + ValueBufferType: Array, - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + DefaultInterpolation: InterpolateDiscrete, - onLoad( scope.parse( JSON.parse( text ) ) ); + InterpolantFactoryMethodLinear: undefined, - }, onProgress, onError ); + InterpolantFactoryMethodSmooth: undefined + +} ); + +/** + * + * A Track of Boolean keyframe values. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function BooleanKeyframeTrack( name, times, values ) { + + KeyframeTrack.call( this, name, times, values ); + +} + +BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + + constructor: BooleanKeyframeTrack, + + ValueTypeName: 'bool', + ValueBufferType: Array, + + DefaultInterpolation: InterpolateDiscrete, + + InterpolantFactoryMethodLinear: undefined, + InterpolantFactoryMethodSmooth: undefined + + // Note: Actually this track could have a optimized / compressed + // representation of a single value and a custom interpolant that + // computes "firstValue ^ isOdd( index )". + +} ); + +/** + * Abstract base class of interpolants over parametric samples. + * + * The parameter domain is one dimensional, typically the time or a path + * along a curve defined by the data. + * + * The sample values can have any dimensionality and derived classes may + * apply special interpretations to the data. + * + * This class provides the interval seek in a Template Method, deferring + * the actual interpolation to derived classes. + * + * Time complexity is O(1) for linear access crossing at most two points + * and O(log N) for random access, where N is the number of positions. + * + * References: + * + * http://www.oodesign.com/template-method-pattern.html + * + * @author tschw + */ + +function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + this.parameterPositions = parameterPositions; + this._cachedIndex = 0; + + this.resultBuffer = resultBuffer !== undefined ? + resultBuffer : new sampleValues.constructor( sampleSize ); + this.sampleValues = sampleValues; + this.valueSize = sampleSize; + +} + +Object.assign( Interpolant.prototype, { + + evaluate: function ( t ) { + + var pp = this.parameterPositions, + i1 = this._cachedIndex, + + t1 = pp[ i1 ], + t0 = pp[ i1 - 1 ]; + + validate_interval: { + + seek: { + + var right; + + linear_scan: { + + //- See http://jsperf.com/comparison-to-undefined/3 + //- slower code: + //- + //- if ( t >= t1 || t1 === undefined ) { + forward_scan: if ( ! ( t < t1 ) ) { + + for ( var giveUpAt = i1 + 2; ; ) { + + if ( t1 === undefined ) { + + if ( t < t0 ) break forward_scan; + + // after end + + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t, t0 ); + + } + + if ( i1 === giveUpAt ) break; // this loop + + t0 = t1; + t1 = pp[ ++ i1 ]; + + if ( t < t1 ) { + + // we have arrived at the sought interval + break seek; + + } + + } + + // prepare binary search on the right side of the index + right = pp.length; + break linear_scan; + + } + + //- slower code: + //- if ( t < t0 || t0 === undefined ) { + if ( ! ( t >= t0 ) ) { + + // looping? + + var t1global = pp[ 1 ]; + + if ( t < t1global ) { + + i1 = 2; // + 1, using the scan for the details + t0 = t1global; + + } + + // linear reverse scan + + for ( var giveUpAt = i1 - 2; ; ) { + + if ( t0 === undefined ) { + + // before start + + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); + + } + + if ( i1 === giveUpAt ) break; // this loop + + t1 = t0; + t0 = pp[ -- i1 - 1 ]; + + if ( t >= t0 ) { + + // we have arrived at the sought interval + break seek; + + } + + } + + // prepare binary search on the left side of the index + right = i1; + i1 = 0; + break linear_scan; + + } + + // the interval is valid + + break validate_interval; + + } // linear scan + + // binary search + + while ( i1 < right ) { + + var mid = ( i1 + right ) >>> 1; + + if ( t < pp[ mid ] ) { + + right = mid; + + } else { + + i1 = mid + 1; + + } + + } + + t1 = pp[ i1 ]; + t0 = pp[ i1 - 1 ]; + + // check boundary cases, again + + if ( t0 === undefined ) { + + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); + + } + + if ( t1 === undefined ) { + + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t0, t ); + + } + + } // seek + + this._cachedIndex = i1; + + this.intervalChanged_( i1, t0, t1 ); + + } // validate_interval + + return this.interpolate_( i1, t0, t, t1 ); }, - parse: function ( json ) { + settings: null, // optional, subclass-specific settings structure + // Note: The indirection allows central control of many interpolants. - var geometry = new BufferGeometry(); + // --- Protected interface - var index = json.data.index; + DefaultSettings_: {}, - if ( index !== undefined ) { + getSettings_: function () { - var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); + return this.settings || this.DefaultSettings_; + + }, + + copySampleValue_: function ( index ) { + + // copies a sample value to the result buffer + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + offset = index * stride; + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = values[ offset + i ]; } - var attributes = json.data.attributes; + return result; - for ( var key in attributes ) { + }, - var attribute = attributes[ key ]; - var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); + // Template methods for derived classes: - geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); + interpolate_: function ( /* i1, t0, t, t1 */ ) { + + throw new Error( 'call to abstract method' ); + // implementations shall return this.resultBuffer + + }, + + intervalChanged_: function ( /* i1, t0, t1 */ ) { + + // empty + + } + +} ); + +//!\ DECLARE ALIAS AFTER assign prototype ! +Object.assign( Interpolant.prototype, { + + //( 0, t, t0 ), returns this.resultBuffer + beforeStart_: Interpolant.prototype.copySampleValue_, + + //( N-1, tN-1, t ), returns this.resultBuffer + afterEnd_: Interpolant.prototype.copySampleValue_, + +} ); + +/** + * Spherical linear unit quaternion interpolant. + * + * @author tschw + */ + +function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + +} + +QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + + constructor: QuaternionLinearInterpolant, + + interpolate_: function ( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + offset = i1 * stride, + + alpha = ( t - t0 ) / ( t1 - t0 ); + + for ( var end = offset + stride; offset !== end; offset += 4 ) { + + Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); } - var groups = json.data.groups || json.data.drawcalls || json.data.offsets; + return result; - if ( groups !== undefined ) { + } - for ( var i = 0, n = groups.length; i !== n; ++ i ) { +} ); - var group = groups[ i ]; +/** + * + * A Track of quaternion keyframe values. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - geometry.addGroup( group.start, group.count, group.materialIndex ); +function QuaternionKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrack.call( this, name, times, values, interpolation ); + +} + +QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + + constructor: QuaternionKeyframeTrack, + + ValueTypeName: 'quaternion', + + // ValueBufferType is inherited + + DefaultInterpolation: InterpolateLinear, + + InterpolantFactoryMethodLinear: function ( result ) { + + return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); + + }, + + InterpolantFactoryMethodSmooth: undefined // not yet implemented + +} ); + +/** + * + * A Track of keyframe values that represent color. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function ColorKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrack.call( this, name, times, values, interpolation ); + +} + +ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + + constructor: ColorKeyframeTrack, + + ValueTypeName: 'color' + + // ValueBufferType is inherited + + // DefaultInterpolation is inherited + + // Note: Very basic implementation and nothing special yet. + // However, this is the place for color space parameterization. + +} ); + +/** + * + * A Track of numeric keyframe values. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ + +function NumberKeyframeTrack( name, times, values, interpolation ) { + + KeyframeTrack.call( this, name, times, values, interpolation ); + +} + +NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + + constructor: NumberKeyframeTrack, + + ValueTypeName: 'number' + + // ValueBufferType is inherited + + // DefaultInterpolation is inherited + +} ); + +/** + * Fast and simple cubic spline interpolant. + * + * It was derived from a Hermitian construction setting the first derivative + * at each sample position to the linear slope between neighboring positions + * over their parameter interval. + * + * @author tschw + */ + +function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + + this._weightPrev = - 0; + this._offsetPrev = - 0; + this._weightNext = - 0; + this._offsetNext = - 0; + +} + +CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + + constructor: CubicInterpolant, + + DefaultSettings_: { + + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + + }, + + intervalChanged_: function ( i1, t0, t1 ) { + + var pp = this.parameterPositions, + iPrev = i1 - 2, + iNext = i1 + 1, + + tPrev = pp[ iPrev ], + tNext = pp[ iNext ]; + + if ( tPrev === undefined ) { + + switch ( this.getSettings_().endingStart ) { + + case ZeroSlopeEnding: + + // f'(t0) = 0 + iPrev = i1; + tPrev = 2 * t0 - t1; + + break; + + case WrapAroundEnding: + + // use the other end of the curve + iPrev = pp.length - 2; + tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(t0) = 0 a.k.a. Natural Spline + iPrev = i1; + tPrev = t1; } } - var boundingSphere = json.data.boundingSphere; + if ( tNext === undefined ) { - if ( boundingSphere !== undefined ) { + switch ( this.getSettings_().endingEnd ) { - var center = new Vector3(); + case ZeroSlopeEnding: - if ( boundingSphere.center !== undefined ) { + // f'(tN) = 0 + iNext = i1; + tNext = 2 * t1 - t0; - center.fromArray( boundingSphere.center ); + break; + + case WrapAroundEnding: + + // use the other end of the curve + iNext = 1; + tNext = t1 + pp[ 1 ] - pp[ 0 ]; + + break; + + default: // ZeroCurvatureEnding + + // f''(tN) = 0, a.k.a. Natural Spline + iNext = i1 - 1; + tNext = t0; } - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); + } + + var halfDt = ( t1 - t0 ) * 0.5, + stride = this.valueSize; + + this._weightPrev = halfDt / ( t0 - tPrev ); + this._weightNext = halfDt / ( tNext - t1 ); + this._offsetPrev = iPrev * stride; + this._offsetNext = iNext * stride; + + }, + + interpolate_: function ( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + o1 = i1 * stride, o0 = o1 - stride, + oP = this._offsetPrev, oN = this._offsetNext, + wP = this._weightPrev, wN = this._weightNext, + + p = ( t - t0 ) / ( t1 - t0 ), + pp = p * p, + ppp = pp * p; + + // evaluate polynomials + + var sP = - wP * ppp + 2 * wP * pp - wP * p; + var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; + var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; + var sN = wN * ppp - wN * pp; + + // combine data linearly + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = + sP * values[ oP + i ] + + s0 * values[ o0 + i ] + + s1 * values[ o1 + i ] + + sN * values[ oN + i ]; } - return geometry; + return result; } } ); -var TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - // Workaround for IE11 pre KB2929437. See #11440 - Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array -}; +/** + * @author tschw + */ + +function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + +} + +LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + + constructor: LinearInterpolant, + + interpolate_: function ( i1, t0, t, t1 ) { + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + + offset1 = i1 * stride, + offset0 = offset1 - stride, + + weight1 = ( t - t0 ) / ( t1 - t0 ), + weight0 = 1 - weight1; + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = + values[ offset0 + i ] * weight0 + + values[ offset1 + i ] * weight1; + + } + + return result; + + } + +} ); /** - * @author alteredq / http://alteredqualia.com/ + * + * Interpolant that evaluates to the sample value at the position preceeding + * the parameter. + * + * @author tschw */ -function Loader() { +function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - this.onLoadStart = function () {}; - this.onLoadProgress = function () {}; - this.onLoadComplete = function () {}; + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); } -Loader.Handlers = { +DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - handlers: [], + constructor: DiscreteInterpolant, - add: function ( regex, loader ) { + interpolate_: function ( i1 /*, t0, t, t1 */ ) { - this.handlers.push( regex, loader ); + return this.copySampleValue_( i1 - 1 ); + + } + +} ); + +/** + * @author tschw + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ + +var AnimationUtils = { + + // same as Array.prototype.slice, but also works on typed arrays + arraySlice: function ( array, from, to ) { + + if ( AnimationUtils.isTypedArray( array ) ) { + + // in ios9 array.subarray(from, undefined) will return empty array + // but array.subarray(from) or array.subarray(from, len) is correct + return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) ); + + } + + return array.slice( from, to ); }, - get: function ( file ) { + // converts an array to a specific type + convertArray: function ( array, type, forceClone ) { + + if ( ! array || // let 'undefined' and 'null' pass + ! forceClone && array.constructor === type ) return array; + + if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { + + return new type( array ); // create typed array + + } + + return Array.prototype.slice.call( array ); // create Array + + }, + + isTypedArray: function ( object ) { + + return ArrayBuffer.isView( object ) && + ! ( object instanceof DataView ); + + }, + + // returns an array by which times and values can be sorted + getKeyframeOrder: function ( times ) { + + function compareTime( i, j ) { + + return times[ i ] - times[ j ]; + + } + + var n = times.length; + var result = new Array( n ); + for ( var i = 0; i !== n; ++ i ) result[ i ] = i; + + result.sort( compareTime ); + + return result; + + }, + + // uses the array previously returned by 'getKeyframeOrder' to sort data + sortedArray: function ( values, stride, order ) { + + var nValues = values.length; + var result = new values.constructor( nValues ); + + for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + + var srcOffset = order[ i ] * stride; + + for ( var j = 0; j !== stride; ++ j ) { + + result[ dstOffset ++ ] = values[ srcOffset + j ]; + + } + + } + + return result; + + }, + + // function for parsing AOS keyframe formats + flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { + + var i = 1, key = jsonKeys[ 0 ]; + + while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + + key = jsonKeys[ i ++ ]; + + } + + if ( key === undefined ) return; // no data + + var value = key[ valuePropertyName ]; + if ( value === undefined ) return; // no data + + if ( Array.isArray( value ) ) { + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + values.push.apply( values, value ); // push all elements + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } else if ( value.toArray !== undefined ) { + + // ...assume THREE.Math-ish + + do { + + value = key[ valuePropertyName ]; + + if ( value !== undefined ) { + + times.push( key.time ); + value.toArray( values, values.length ); + + } + + key = jsonKeys[ i ++ ]; + + } while ( key !== undefined ); + + } else { + + // otherwise push as-is + + do { - var handlers = this.handlers; + value = key[ valuePropertyName ]; - for ( var i = 0, l = handlers.length; i < l; i += 2 ) { + if ( value !== undefined ) { - var regex = handlers[ i ]; - var loader = handlers[ i + 1 ]; + times.push( key.time ); + values.push( value ); - if ( regex.test( file ) ) { + } - return loader; + key = jsonKeys[ i ++ ]; - } + } while ( key !== undefined ); } - return null; - } }; -Object.assign( Loader.prototype, { - - crossOrigin: undefined, +/** + * + * A timed sequence of keyframes for a specific property. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - initMaterials: function ( materials, texturePath, crossOrigin ) { +function KeyframeTrack( name, times, values, interpolation ) { - var array = []; + if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); + if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); - for ( var i = 0; i < materials.length; ++ i ) { + this.name = name; - array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); + this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); + this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); - } + this.setInterpolation( interpolation || this.DefaultInterpolation ); - return array; + this.validate(); + this.optimize(); - }, +} - createMaterial: ( function () { +// Static methods: - var BlendingMode = { - NoBlending: NoBlending, - NormalBlending: NormalBlending, - AdditiveBlending: AdditiveBlending, - SubtractiveBlending: SubtractiveBlending, - MultiplyBlending: MultiplyBlending, - CustomBlending: CustomBlending - }; +Object.assign( KeyframeTrack, { - var color = new Color(); - var textureLoader = new TextureLoader(); - var materialLoader = new MaterialLoader(); + // Serialization (in static context, because of constructor invocation + // and automatic invocation of .toJSON): - return function createMaterial( m, texturePath, crossOrigin ) { + parse: function ( json ) { - // convert from old material format + if ( json.type === undefined ) { - var textures = {}; + throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); - function loadTexture( path, repeat, offset, wrap, anisotropy ) { + } - var fullPath = texturePath + path; - var loader = Loader.Handlers.get( fullPath ); + var trackType = KeyframeTrack._getTrackTypeForValueTypeName( json.type ); - var texture; + if ( json.times === undefined ) { - if ( loader !== null ) { + var times = [], values = []; - texture = loader.load( fullPath ); + AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); - } else { + json.times = times; + json.values = values; - textureLoader.setCrossOrigin( crossOrigin ); - texture = textureLoader.load( fullPath ); + } - } + // derived classes can define a static parse method + if ( trackType.parse !== undefined ) { - if ( repeat !== undefined ) { + return trackType.parse( json ); - texture.repeat.fromArray( repeat ); + } else { - if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; + // by default, we assume a constructor compatible with the base + return new trackType( json.name, json.times, json.values, json.interpolation ); - } + } - if ( offset !== undefined ) { + }, - texture.offset.fromArray( offset ); + toJSON: function ( track ) { - } + var trackType = track.constructor; - if ( wrap !== undefined ) { + var json; - if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; - if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; + // derived classes can define a static toJSON method + if ( trackType.toJSON !== undefined ) { - if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; - if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; + json = trackType.toJSON( track ); - } + } else { - if ( anisotropy !== undefined ) { + // by default, we assume the data can be serialized as-is + json = { - texture.anisotropy = anisotropy; + 'name': track.name, + 'times': AnimationUtils.convertArray( track.times, Array ), + 'values': AnimationUtils.convertArray( track.values, Array ) - } + }; - var uuid = _Math.generateUUID(); + var interpolation = track.getInterpolation(); - textures[ uuid ] = texture; + if ( interpolation !== track.DefaultInterpolation ) { - return uuid; + json.interpolation = interpolation; } - // - - var json = { - uuid: _Math.generateUUID(), - type: 'MeshLambertMaterial' - }; - - for ( var name in m ) { + } - var value = m[ name ]; + json.type = track.ValueTypeName; // mandatory - switch ( name ) { + return json; - case 'DbgColor': - case 'DbgIndex': - case 'opticalDensity': - case 'illumination': - break; - case 'DbgName': - json.name = value; - break; - case 'blending': - json.blending = BlendingMode[ value ]; - break; - case 'colorAmbient': - case 'mapAmbient': - console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); - break; - case 'colorDiffuse': - json.color = color.fromArray( value ).getHex(); - break; - case 'colorSpecular': - json.specular = color.fromArray( value ).getHex(); - break; - case 'colorEmissive': - json.emissive = color.fromArray( value ).getHex(); - break; - case 'specularCoef': - json.shininess = value; - break; - case 'shading': - if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; - if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; - if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; - break; - case 'mapDiffuse': - json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - break; - case 'mapDiffuseRepeat': - case 'mapDiffuseOffset': - case 'mapDiffuseWrap': - case 'mapDiffuseAnisotropy': - break; - case 'mapEmissive': - json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); - break; - case 'mapEmissiveRepeat': - case 'mapEmissiveOffset': - case 'mapEmissiveWrap': - case 'mapEmissiveAnisotropy': - break; - case 'mapLight': - json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - break; - case 'mapLightRepeat': - case 'mapLightOffset': - case 'mapLightWrap': - case 'mapLightAnisotropy': - break; - case 'mapAO': - json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); - break; - case 'mapAORepeat': - case 'mapAOOffset': - case 'mapAOWrap': - case 'mapAOAnisotropy': - break; - case 'mapBump': - json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - break; - case 'mapBumpScale': - json.bumpScale = value; - break; - case 'mapBumpRepeat': - case 'mapBumpOffset': - case 'mapBumpWrap': - case 'mapBumpAnisotropy': - break; - case 'mapNormal': - json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - break; - case 'mapNormalFactor': - json.normalScale = [ value, value ]; - break; - case 'mapNormalRepeat': - case 'mapNormalOffset': - case 'mapNormalWrap': - case 'mapNormalAnisotropy': - break; - case 'mapSpecular': - json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - break; - case 'mapSpecularRepeat': - case 'mapSpecularOffset': - case 'mapSpecularWrap': - case 'mapSpecularAnisotropy': - break; - case 'mapMetalness': - json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); - break; - case 'mapMetalnessRepeat': - case 'mapMetalnessOffset': - case 'mapMetalnessWrap': - case 'mapMetalnessAnisotropy': - break; - case 'mapRoughness': - json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); - break; - case 'mapRoughnessRepeat': - case 'mapRoughnessOffset': - case 'mapRoughnessWrap': - case 'mapRoughnessAnisotropy': - break; - case 'mapAlpha': - json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - break; - case 'mapAlphaRepeat': - case 'mapAlphaOffset': - case 'mapAlphaWrap': - case 'mapAlphaAnisotropy': - break; - case 'flipSided': - json.side = BackSide; - break; - case 'doubleSided': - json.side = DoubleSide; - break; - case 'transparency': - console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); - json.opacity = value; - break; - case 'depthTest': - case 'depthWrite': - case 'colorWrite': - case 'opacity': - case 'reflectivity': - case 'transparent': - case 'visible': - case 'wireframe': - json[ name ] = value; - break; - case 'vertexColors': - if ( value === true ) json.vertexColors = VertexColors; - if ( value === 'face' ) json.vertexColors = FaceColors; - break; - default: - console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); - break; + }, - } + _getTrackTypeForValueTypeName: function ( typeName ) { - } + switch ( typeName.toLowerCase() ) { - if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; - if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; + case 'scalar': + case 'double': + case 'float': + case 'number': + case 'integer': - if ( json.opacity < 1 ) json.transparent = true; + return NumberKeyframeTrack; - materialLoader.setTextures( textures ); + case 'vector': + case 'vector2': + case 'vector3': + case 'vector4': - return materialLoader.parse( json ); + return VectorKeyframeTrack; - }; + case 'color': - } )() + return ColorKeyframeTrack; -} ); + case 'quaternion': -/** - * @author Don McCurdy / https://www.donmccurdy.com - */ + return QuaternionKeyframeTrack; -var LoaderUtils = { + case 'bool': + case 'boolean': - decodeText: function ( array ) { + return BooleanKeyframeTrack; - if ( typeof TextDecoder !== 'undefined' ) { + case 'string': - return new TextDecoder().decode( array ); + return StringKeyframeTrack; } - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. + throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - var s = ''; + } - for ( var i = 0, il = array.length; i < il; i ++ ) { +} ); - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); +Object.assign( KeyframeTrack.prototype, { - } + constructor: KeyframeTrack, - return s; + TimeBufferType: Float32Array, - }, + ValueBufferType: Float32Array, - extractUrlBase: function ( url ) { + DefaultInterpolation: InterpolateLinear, - var parts = url.split( '/' ); + InterpolantFactoryMethodDiscrete: function ( result ) { - if ( parts.length === 1 ) return './'; + return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); - parts.pop(); + }, - return parts.join( '/' ) + '/'; + InterpolantFactoryMethodLinear: function ( result ) { - } + return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); -}; + }, -/** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + InterpolantFactoryMethodSmooth: function ( result ) { -function JSONLoader( manager ) { + return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); - if ( typeof manager === 'boolean' ) { + }, - console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); - manager = undefined; + setInterpolation: function ( interpolation ) { - } + var factoryMethod; - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + switch ( interpolation ) { - this.withCredentials = false; + case InterpolateDiscrete: -} + factoryMethod = this.InterpolantFactoryMethodDiscrete; -Object.assign( JSONLoader.prototype, { + break; - load: function ( url, onLoad, onProgress, onError ) { + case InterpolateLinear: - var scope = this; + factoryMethod = this.InterpolantFactoryMethodLinear; - var texturePath = this.texturePath && ( typeof this.texturePath === 'string' ) ? this.texturePath : LoaderUtils.extractUrlBase( url ); + break; - var loader = new FileLoader( this.manager ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { + case InterpolateSmooth: - var json = JSON.parse( text ); - var metadata = json.metadata; + factoryMethod = this.InterpolantFactoryMethodSmooth; - if ( metadata !== undefined ) { + break; - var type = metadata.type; + } - if ( type !== undefined ) { + if ( factoryMethod === undefined ) { - if ( type.toLowerCase() === 'object' ) { + var message = "unsupported interpolation for " + + this.ValueTypeName + " keyframe track named " + this.name; - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); - return; + if ( this.createInterpolant === undefined ) { - } + // fall back to default, unless the default itself is messed up + if ( interpolation !== this.DefaultInterpolation ) { - if ( type.toLowerCase() === 'scene' ) { + this.setInterpolation( this.DefaultInterpolation ); - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); - return; + } else { - } + throw new Error( message ); // fatal, in this case } } - var object = scope.parse( json, texturePath ); - onLoad( object.geometry, object.materials ); - - }, onProgress, onError ); - - }, + console.warn( 'THREE.KeyframeTrack:', message ); + return; - setTexturePath: function ( value ) { + } - this.texturePath = value; + this.createInterpolant = factoryMethod; }, - parse: ( function () { - - function parseModel( json, geometry ) { - - function isBitSet( value, position ) { + getInterpolation: function () { - return value & ( 1 << position ); + switch ( this.createInterpolant ) { - } + case this.InterpolantFactoryMethodDiscrete: - var i, j, fi, + return InterpolateDiscrete; - offset, zLength, + case this.InterpolantFactoryMethodLinear: - colorIndex, normalIndex, uvIndex, materialIndex, + return InterpolateLinear; - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, + case this.InterpolantFactoryMethodSmooth: - vertex, face, faceA, faceB, hex, normal, + return InterpolateSmooth; - uvLayer, uv, u, v, + } - faces = json.faces, - vertices = json.vertices, - normals = json.normals, - colors = json.colors, + }, - scale = json.scale, + getValueSize: function () { - nUvLayers = 0; + return this.values.length / this.times.length; + }, - if ( json.uvs !== undefined ) { + // move all keyframes either forwards or backwards in time + shift: function ( timeOffset ) { - // disregard empty arrays + if ( timeOffset !== 0.0 ) { - for ( i = 0; i < json.uvs.length; i ++ ) { + var times = this.times; - if ( json.uvs[ i ].length ) nUvLayers ++; + for ( var i = 0, n = times.length; i !== n; ++ i ) { - } + times[ i ] += timeOffset; - for ( i = 0; i < nUvLayers; i ++ ) { + } - geometry.faceVertexUvs[ i ] = []; + } - } + return this; - } + }, - offset = 0; - zLength = vertices.length; + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale: function ( timeScale ) { - while ( offset < zLength ) { + if ( timeScale !== 1.0 ) { - vertex = new Vector3(); + var times = this.times; - vertex.x = vertices[ offset ++ ] * scale; - vertex.y = vertices[ offset ++ ] * scale; - vertex.z = vertices[ offset ++ ] * scale; + for ( var i = 0, n = times.length; i !== n; ++ i ) { - geometry.vertices.push( vertex ); + times[ i ] *= timeScale; } - offset = 0; - zLength = faces.length; - - while ( offset < zLength ) { - - type = faces[ offset ++ ]; + } - isQuad = isBitSet( type, 0 ); - hasMaterial = isBitSet( type, 1 ); - hasFaceVertexUv = isBitSet( type, 3 ); - hasFaceNormal = isBitSet( type, 4 ); - hasFaceVertexNormal = isBitSet( type, 5 ); - hasFaceColor = isBitSet( type, 6 ); - hasFaceVertexColor = isBitSet( type, 7 ); + return this; - // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); + }, - if ( isQuad ) { + // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. + // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values + trim: function ( startTime, endTime ) { - faceA = new Face3(); - faceA.a = faces[ offset ]; - faceA.b = faces[ offset + 1 ]; - faceA.c = faces[ offset + 3 ]; + var times = this.times, + nKeys = times.length, + from = 0, + to = nKeys - 1; - faceB = new Face3(); - faceB.a = faces[ offset + 1 ]; - faceB.b = faces[ offset + 2 ]; - faceB.c = faces[ offset + 3 ]; + while ( from !== nKeys && times[ from ] < startTime ) { - offset += 4; + ++ from; - if ( hasMaterial ) { + } - materialIndex = faces[ offset ++ ]; - faceA.materialIndex = materialIndex; - faceB.materialIndex = materialIndex; + while ( to !== - 1 && times[ to ] > endTime ) { - } + -- to; - // to get face <=> uv index correspondence + } - fi = geometry.faces.length; + ++ to; // inclusive -> exclusive bound - if ( hasFaceVertexUv ) { + if ( from !== 0 || to !== nKeys ) { - for ( i = 0; i < nUvLayers; i ++ ) { + // empty tracks are forbidden, so keep at least one keyframe + if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; - uvLayer = json.uvs[ i ]; + var stride = this.getValueSize(); + this.times = AnimationUtils.arraySlice( times, from, to ); + this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); - geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi + 1 ] = []; + } - for ( j = 0; j < 4; j ++ ) { + return this; - uvIndex = faces[ offset ++ ]; + }, - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable + validate: function () { - uv = new Vector2( u, v ); + var valid = true; - if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); - if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); + var valueSize = this.getValueSize(); + if ( valueSize - Math.floor( valueSize ) !== 0 ) { - } + console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); + valid = false; - } + } - } + var times = this.times, + values = this.values, - if ( hasFaceNormal ) { + nKeys = times.length; - normalIndex = faces[ offset ++ ] * 3; + if ( nKeys === 0 ) { - faceA.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + console.error( 'THREE.KeyframeTrack: Track is empty.', this ); + valid = false; - faceB.normal.copy( faceA.normal ); + } - } + var prevTime = null; - if ( hasFaceVertexNormal ) { + for ( var i = 0; i !== nKeys; i ++ ) { - for ( i = 0; i < 4; i ++ ) { + var currTime = times[ i ]; - normalIndex = faces[ offset ++ ] * 3; + if ( typeof currTime === 'number' && isNaN( currTime ) ) { - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); + valid = false; + break; + } - if ( i !== 2 ) faceA.vertexNormals.push( normal ); - if ( i !== 0 ) faceB.vertexNormals.push( normal ); + if ( prevTime !== null && prevTime > currTime ) { - } + console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); + valid = false; + break; - } + } + prevTime = currTime; - if ( hasFaceColor ) { + } - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + if ( values !== undefined ) { - faceA.color.setHex( hex ); - faceB.color.setHex( hex ); + if ( AnimationUtils.isTypedArray( values ) ) { - } + for ( var i = 0, n = values.length; i !== n; ++ i ) { + var value = values[ i ]; - if ( hasFaceVertexColor ) { + if ( isNaN( value ) ) { - for ( i = 0; i < 4; i ++ ) { + console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); + valid = false; + break; - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + } - if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); + } - } + } - } + } - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); + return valid; - } else { + }, - face = new Face3(); - face.a = faces[ offset ++ ]; - face.b = faces[ offset ++ ]; - face.c = faces[ offset ++ ]; + // removes equivalent sequential keys as common in morph target sequences + // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) + optimize: function () { - if ( hasMaterial ) { + var times = this.times, + values = this.values, + stride = this.getValueSize(), - materialIndex = faces[ offset ++ ]; - face.materialIndex = materialIndex; + smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - } + writeIndex = 1, + lastIndex = times.length - 1; - // to get face <=> uv index correspondence + for ( var i = 1; i < lastIndex; ++ i ) { - fi = geometry.faces.length; + var keep = false; - if ( hasFaceVertexUv ) { + var time = times[ i ]; + var timeNext = times[ i + 1 ]; - for ( i = 0; i < nUvLayers; i ++ ) { + // remove adjacent keyframes scheduled at the same time - uvLayer = json.uvs[ i ]; + if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { - geometry.faceVertexUvs[ i ][ fi ] = []; + if ( ! smoothInterpolation ) { - for ( j = 0; j < 3; j ++ ) { + // remove unnecessary keyframes same as their neighbors - uvIndex = faces[ offset ++ ]; + var offset = i * stride, + offsetP = offset - stride, + offsetN = offset + stride; - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + for ( var j = 0; j !== stride; ++ j ) { - uv = new Vector2( u, v ); + var value = values[ offset + j ]; - geometry.faceVertexUvs[ i ][ fi ].push( uv ); + if ( value !== values[ offsetP + j ] || + value !== values[ offsetN + j ] ) { - } + keep = true; + break; } } - if ( hasFaceNormal ) { + } else { - normalIndex = faces[ offset ++ ] * 3; + keep = true; - face.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + } - } + } - if ( hasFaceVertexNormal ) { + // in-place compaction - for ( i = 0; i < 3; i ++ ) { + if ( keep ) { - normalIndex = faces[ offset ++ ] * 3; + if ( i !== writeIndex ) { - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + times[ writeIndex ] = times[ i ]; - face.vertexNormals.push( normal ); + var readOffset = i * stride, + writeOffset = writeIndex * stride; - } + for ( var j = 0; j !== stride; ++ j ) { + + values[ writeOffset + j ] = values[ readOffset + j ]; } + } - if ( hasFaceColor ) { + ++ writeIndex; - colorIndex = faces[ offset ++ ]; - face.color.setHex( colors[ colorIndex ] ); + } - } + } + // flush last keyframe (compaction looks ahead) - if ( hasFaceVertexColor ) { + if ( lastIndex > 0 ) { - for ( i = 0; i < 3; i ++ ) { + times[ writeIndex ] = times[ lastIndex ]; - colorIndex = faces[ offset ++ ]; - face.vertexColors.push( new Color( colors[ colorIndex ] ) ); + for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { - } + values[ writeOffset + j ] = values[ readOffset + j ]; - } + } - geometry.faces.push( face ); + ++ writeIndex; - } + } - } + if ( writeIndex !== times.length ) { - } + this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); + this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); - function parseSkin( json, geometry ) { + } - var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; + return this; - if ( json.skinWeights ) { + } - for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { +} ); - var x = json.skinWeights[ i ]; - var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; - var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; - var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; +/** + * + * A Track of vectored keyframe values. + * + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + * @author tschw + */ - geometry.skinWeights.push( new Vector4( x, y, z, w ) ); +function VectorKeyframeTrack( name, times, values, interpolation ) { - } + KeyframeTrack.call( this, name, times, values, interpolation ); - } +} - if ( json.skinIndices ) { +VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { + constructor: VectorKeyframeTrack, - var a = json.skinIndices[ i ]; - var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; - var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; - var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; + ValueTypeName: 'vector' - geometry.skinIndices.push( new Vector4( a, b, c, d ) ); + // ValueBufferType is inherited - } + // DefaultInterpolation is inherited - } +} ); - geometry.bones = json.bones; +/** + * + * Reusable set of Tracks that represent an animation. + * + * @author Ben Houston / http://clara.io/ + * @author David Sarno / http://lighthaus.us/ + */ - if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { +function AnimationClip( name, duration, tracks ) { - console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); + this.name = name; + this.tracks = tracks; + this.duration = ( duration !== undefined ) ? duration : - 1; - } + this.uuid = _Math.generateUUID(); - } + // this means it should figure out its duration by scanning the tracks + if ( this.duration < 0 ) { - function parseMorphing( json, geometry ) { + this.resetDuration(); - var scale = json.scale; + } - if ( json.morphTargets !== undefined ) { + this.optimize(); - for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { +} - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; +Object.assign( AnimationClip, { - var dstVertices = geometry.morphTargets[ i ].vertices; - var srcVertices = json.morphTargets[ i ].vertices; + parse: function ( json ) { - for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + var tracks = [], + jsonTracks = json.tracks, + frameTime = 1.0 / ( json.fps || 1.0 ); - var vertex = new Vector3(); - vertex.x = srcVertices[ v ] * scale; - vertex.y = srcVertices[ v + 1 ] * scale; - vertex.z = srcVertices[ v + 2 ] * scale; + for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { - dstVertices.push( vertex ); + tracks.push( KeyframeTrack.parse( jsonTracks[ i ] ).scale( frameTime ) ); - } + } - } + return new AnimationClip( json.name, json.duration, tracks ); - } + }, - if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { + toJSON: function ( clip ) { - console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); + var tracks = [], + clipTracks = clip.tracks; - var faces = geometry.faces; - var morphColors = json.morphColors[ 0 ].colors; + var json = { - for ( var i = 0, l = faces.length; i < l; i ++ ) { + 'name': clip.name, + 'duration': clip.duration, + 'tracks': tracks - faces[ i ].color.fromArray( morphColors, i * 3 ); + }; - } + for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { - } + tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); } - function parseAnimations( json, geometry ) { - - var outputAnimations = []; + return json; - // parse old style Bone/Hierarchy animations - var animations = []; + }, - if ( json.animation !== undefined ) { + CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { - animations.push( json.animation ); + var numMorphTargets = morphTargetSequence.length; + var tracks = []; - } + for ( var i = 0; i < numMorphTargets; i ++ ) { - if ( json.animations !== undefined ) { + var times = []; + var values = []; - if ( json.animations.length ) { + times.push( + ( i + numMorphTargets - 1 ) % numMorphTargets, + i, + ( i + 1 ) % numMorphTargets ); - animations = animations.concat( json.animations ); + values.push( 0, 1, 0 ); - } else { + var order = AnimationUtils.getKeyframeOrder( times ); + times = AnimationUtils.sortedArray( times, 1, order ); + values = AnimationUtils.sortedArray( values, 1, order ); - animations.push( json.animations ); + // if there is a key at the first frame, duplicate it as the + // last frame as well for perfect loop. + if ( ! noLoop && times[ 0 ] === 0 ) { - } + times.push( numMorphTargets ); + values.push( values[ 0 ] ); } - for ( var i = 0; i < animations.length; i ++ ) { + tracks.push( + new NumberKeyframeTrack( + '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', + times, values + ).scale( 1.0 / fps ) ); - var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); - if ( clip ) outputAnimations.push( clip ); + } - } + return new AnimationClip( name, - 1, tracks ); - // parse implicit morph animations - if ( geometry.morphTargets ) { + }, - // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. - var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); - outputAnimations = outputAnimations.concat( morphAnimationClips ); + findByName: function ( objectOrClipArray, name ) { - } + var clipArray = objectOrClipArray; - if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; + if ( ! Array.isArray( objectOrClipArray ) ) { + + var o = objectOrClipArray; + clipArray = o.geometry && o.geometry.animations || o.animations; } - return function ( json, texturePath ) { + for ( var i = 0; i < clipArray.length; i ++ ) { - if ( json.data !== undefined ) { + if ( clipArray[ i ].name === name ) { - // Geometry 4.0 spec - json = json.data; + return clipArray[ i ]; } - if ( json.scale !== undefined ) { + } - json.scale = 1.0 / json.scale; + return null; - } else { + }, - json.scale = 1.0; + CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { - } + var animationToMorphTargets = {}; - var geometry = new Geometry(); + // tested with https://regex101.com/ on trick sequences + // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + var pattern = /^([\w-]*?)([\d]+)$/; - parseModel( json, geometry ); - parseSkin( json, geometry ); - parseMorphing( json, geometry ); - parseAnimations( json, geometry ); + // sort morph target names into animation groups based + // patterns like Walk_001, Walk_002, Run_001, Run_002 + for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); + var morphTarget = morphTargets[ i ]; + var parts = morphTarget.name.match( pattern ); - if ( json.materials === undefined || json.materials.length === 0 ) { + if ( parts && parts.length > 1 ) { - return { geometry: geometry }; + var name = parts[ 1 ]; - } else { + var animationMorphTargets = animationToMorphTargets[ name ]; + if ( ! animationMorphTargets ) { - var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); + animationToMorphTargets[ name ] = animationMorphTargets = []; - return { geometry: geometry, materials: materials }; + } - } + animationMorphTargets.push( morphTarget ); - }; + } - } )() + } -} ); + var clips = []; -/** - * @author mrdoob / http://mrdoob.com/ - */ + for ( var name in animationToMorphTargets ) { -function ObjectLoader( manager ) { + clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.texturePath = ''; + } -} + return clips; -Object.assign( ObjectLoader.prototype, { + }, - load: function ( url, onLoad, onProgress, onError ) { + // parse the animation.hierarchy format + parseAnimation: function ( animation, bones ) { - if ( this.texturePath === '' ) { + if ( ! animation ) { - this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); + console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); + return null; } - var scope = this; + var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - var loader = new FileLoader( scope.manager ); - loader.load( url, function ( text ) { + // only return track if there are actually keys. + if ( animationKeys.length !== 0 ) { + + var times = []; + var values = []; + + AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); + + // empty keys are filtered out, so check again + if ( times.length !== 0 ) { + + destTracks.push( new trackType( trackName, times, values ) ); + + } + + } + + }; - var json = null; + var tracks = []; - try { + var clipName = animation.name || 'default'; + // automatic length determination in AnimationClip. + var duration = animation.length || - 1; + var fps = animation.fps || 30; - json = JSON.parse( text ); + var hierarchyTracks = animation.hierarchy || []; - } catch ( error ) { + for ( var h = 0; h < hierarchyTracks.length; h ++ ) { - if ( onError !== undefined ) onError( error ); + var animationKeys = hierarchyTracks[ h ].keys; - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); + // skip empty tracks + if ( ! animationKeys || animationKeys.length === 0 ) continue; - return; + // process morph targets + if ( animationKeys[ 0 ].morphTargets ) { - } + // figure out all morph targets used in this track + var morphTargetNames = {}; - var metadata = json.metadata; + for ( var k = 0; k < animationKeys.length; k ++ ) { - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + if ( animationKeys[ k ].morphTargets ) { - console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); - return; + for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - } + morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - scope.parse( json, onLoad ); + } - }, onProgress, onError ); + } - }, + } - setTexturePath: function ( value ) { + // create a track for each morph target with all zero + // morphTargetInfluences except for the keys in which + // the morphTarget is named. + for ( var morphTargetName in morphTargetNames ) { - this.texturePath = value; + var times = []; + var values = []; - }, + for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - setCrossOrigin: function ( value ) { + var animationKey = animationKeys[ k ]; - this.crossOrigin = value; + times.push( animationKey.time ); + values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - }, + } - parse: function ( json, onLoad ) { + tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - var geometries = this.parseGeometries( json.geometries ); + } - var images = this.parseImages( json.images, function () { + duration = morphTargetNames.length * ( fps || 1.0 ); - if ( onLoad !== undefined ) onLoad( object ); + } else { - } ); + // ...assume skeletal animation - var textures = this.parseTextures( json.textures, images ); - var materials = this.parseMaterials( json.materials, textures ); + var boneName = '.bones[' + bones[ h ].name + ']'; - var object = this.parseObject( json.object, geometries, materials ); + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.position', + animationKeys, 'pos', tracks ); - if ( json.animations ) { + addNonemptyTrack( + QuaternionKeyframeTrack, boneName + '.quaternion', + animationKeys, 'rot', tracks ); - object.animations = this.parseAnimations( json.animations ); + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.scale', + animationKeys, 'scl', tracks ); + + } } - if ( json.images === undefined || json.images.length === 0 ) { + if ( tracks.length === 0 ) { - if ( onLoad !== undefined ) onLoad( object ); + return null; } - return object; - - }, + var clip = new AnimationClip( clipName, duration, tracks ); - parseGeometries: function ( json ) { + return clip; - var geometries = {}; + } - if ( json !== undefined ) { +} ); - var geometryLoader = new JSONLoader(); - var bufferGeometryLoader = new BufferGeometryLoader(); +Object.assign( AnimationClip.prototype, { - for ( var i = 0, l = json.length; i < l; i ++ ) { + resetDuration: function () { - var geometry; - var data = json[ i ]; + var tracks = this.tracks, duration = 0; - switch ( data.type ) { + for ( var i = 0, n = tracks.length; i !== n; ++ i ) { - case 'PlaneGeometry': - case 'PlaneBufferGeometry': + var track = this.tracks[ i ]; - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - break; + } - case 'BoxGeometry': - case 'BoxBufferGeometry': - case 'CubeGeometry': // backwards compatible + this.duration = duration; - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); + }, - break; + trim: function () { - case 'CircleGeometry': - case 'CircleBufferGeometry': + for ( var i = 0; i < this.tracks.length; i ++ ) { - geometry = new Geometries[ data.type ]( - data.radius, - data.segments, - data.thetaStart, - data.thetaLength - ); + this.tracks[ i ].trim( 0, this.duration ); - break; + } - case 'CylinderGeometry': - case 'CylinderBufferGeometry': + return this; - geometry = new Geometries[ data.type ]( - data.radiusTop, - data.radiusBottom, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded, - data.thetaStart, - data.thetaLength - ); + }, - break; + optimize: function () { - case 'ConeGeometry': - case 'ConeBufferGeometry': + for ( var i = 0; i < this.tracks.length; i ++ ) { - geometry = new Geometries[ data.type ]( - data.radius, - data.height, - data.radialSegments, - data.heightSegments, - data.openEnded, - data.thetaStart, - data.thetaLength - ); + this.tracks[ i ].optimize(); - break; + } - case 'SphereGeometry': - case 'SphereBufferGeometry': + return this; - geometry = new Geometries[ data.type ]( - data.radius, - data.widthSegments, - data.heightSegments, - data.phiStart, - data.phiLength, - data.thetaStart, - data.thetaLength - ); + } - break; +} ); - case 'DodecahedronGeometry': - case 'DodecahedronBufferGeometry': - case 'IcosahedronGeometry': - case 'IcosahedronBufferGeometry': - case 'OctahedronGeometry': - case 'OctahedronBufferGeometry': - case 'TetrahedronGeometry': - case 'TetrahedronBufferGeometry': +/** + * @author mrdoob / http://mrdoob.com/ + */ - geometry = new Geometries[ data.type ]( - data.radius, - data.detail - ); +function MaterialLoader( manager ) { - break; + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.textures = {}; - case 'RingGeometry': - case 'RingBufferGeometry': +} - geometry = new Geometries[ data.type ]( - data.innerRadius, - data.outerRadius, - data.thetaSegments, - data.phiSegments, - data.thetaStart, - data.thetaLength - ); +Object.assign( MaterialLoader.prototype, { - break; + load: function ( url, onLoad, onProgress, onError ) { - case 'TorusGeometry': - case 'TorusBufferGeometry': + var scope = this; - geometry = new Geometries[ data.type ]( - data.radius, - data.tube, - data.radialSegments, - data.tubularSegments, - data.arc - ); + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { - break; + onLoad( scope.parse( JSON.parse( text ) ) ); - case 'TorusKnotGeometry': - case 'TorusKnotBufferGeometry': + }, onProgress, onError ); - geometry = new Geometries[ data.type ]( - data.radius, - data.tube, - data.tubularSegments, - data.radialSegments, - data.p, - data.q - ); + }, - break; + setTextures: function ( value ) { - case 'LatheGeometry': - case 'LatheBufferGeometry': + this.textures = value; - geometry = new Geometries[ data.type ]( - data.points, - data.segments, - data.phiStart, - data.phiLength - ); + }, - break; + parse: function ( json ) { - case 'PolyhedronGeometry': - case 'PolyhedronBufferGeometry': + var textures = this.textures; - geometry = new Geometries[ data.type ]( - data.vertices, - data.indices, - data.radius, - data.details - ); + function getTexture( name ) { - break; + if ( textures[ name ] === undefined ) { - case 'BufferGeometry': + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); - geometry = bufferGeometryLoader.parse( data ); + } - break; + return textures[ name ]; - case 'Geometry': + } - geometry = geometryLoader.parse( data, this.texturePath ).geometry; + var material = new Materials[ json.type ](); - break; + if ( json.uuid !== undefined ) material.uuid = json.uuid; + if ( json.name !== undefined ) material.name = json.name; + if ( json.color !== undefined ) material.color.setHex( json.color ); + if ( json.roughness !== undefined ) material.roughness = json.roughness; + if ( json.metalness !== undefined ) material.metalness = json.metalness; + if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); + if ( json.specular !== undefined ) material.specular.setHex( json.specular ); + if ( json.shininess !== undefined ) material.shininess = json.shininess; + if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; + if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; + if ( json.uniforms !== undefined ) material.uniforms = json.uniforms; + if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; + if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; + if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; + if ( json.fog !== undefined ) material.fog = json.fog; + if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; + if ( json.blending !== undefined ) material.blending = json.blending; + if ( json.side !== undefined ) material.side = json.side; + if ( json.opacity !== undefined ) material.opacity = json.opacity; + if ( json.transparent !== undefined ) material.transparent = json.transparent; + if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; + if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; + if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; + if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; + if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; + if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; + if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; + if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; - default: + if ( json.rotation !== undefined ) material.rotation = json.rotation; - console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); + if ( json.linewidth !== 1 ) material.linewidth = json.linewidth; + if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; + if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; + if ( json.scale !== undefined ) material.scale = json.scale; - continue; + if ( json.skinning !== undefined ) material.skinning = json.skinning; + if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; + if ( json.dithering !== undefined ) material.dithering = json.dithering; - } + if ( json.visible !== undefined ) material.visible = json.visible; + if ( json.userData !== undefined ) material.userData = json.userData; - geometry.uuid = data.uuid; + // Deprecated - if ( data.name !== undefined ) geometry.name = data.name; + if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading - geometries[ data.uuid ] = geometry; + // for PointsMaterial - } + if ( json.size !== undefined ) material.size = json.size; + if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - } + // maps - return geometries; + if ( json.map !== undefined ) material.map = getTexture( json.map ); - }, + if ( json.alphaMap !== undefined ) { - parseMaterials: function ( json, textures ) { + material.alphaMap = getTexture( json.alphaMap ); + material.transparent = true; - var materials = {}; + } - if ( json !== undefined ) { + if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); + if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; - var loader = new MaterialLoader(); - loader.setTextures( textures ); + if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); + if ( json.normalScale !== undefined ) { - for ( var i = 0, l = json.length; i < l; i ++ ) { + var normalScale = json.normalScale; - var data = json[ i ]; + if ( Array.isArray( normalScale ) === false ) { - if ( data.type === 'MultiMaterial' ) { + // Blender exporter used to export a scalar. See #7459 - // Deprecated + normalScale = [ normalScale, normalScale ]; - var array = []; + } - for ( var j = 0; j < data.materials.length; j ++ ) { + material.normalScale = new Vector2().fromArray( normalScale ); - array.push( loader.parse( data.materials[ j ] ) ); + } - } + if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); + if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; + if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; - materials[ data.uuid ] = array; + if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); + if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); - } else { + if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); + if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; - materials[ data.uuid ] = loader.parse( data ); + if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); - } + if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - } + if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - } + if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); + if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - return materials; + if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); + if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; - }, + if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); - parseAnimations: function ( json ) { + return material; - var animations = []; + } - for ( var i = 0; i < json.length; i ++ ) { +} ); - var clip = AnimationClip.parse( json[ i ] ); +/** + * @author mrdoob / http://mrdoob.com/ + */ - animations.push( clip ); +function BufferGeometryLoader( manager ) { - } + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - return animations; +} - }, +Object.assign( BufferGeometryLoader.prototype, { - parseImages: function ( json, onLoad ) { + load: function ( url, onLoad, onProgress, onError ) { var scope = this; - var images = {}; - function loadImage( url ) { - - scope.manager.itemStart( url ); + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { - return loader.load( url, function () { + onLoad( scope.parse( JSON.parse( text ) ) ); - scope.manager.itemEnd( url ); + }, onProgress, onError ); - }, undefined, function () { + }, - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + parse: function ( json ) { - } ); + var geometry = new BufferGeometry(); - } + var index = json.data.index; - if ( json !== undefined && json.length > 0 ) { + if ( index !== undefined ) { - var manager = new LoadingManager( onLoad ); + var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); + geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - var loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); + } - for ( var i = 0, l = json.length; i < l; i ++ ) { + var attributes = json.data.attributes; - var image = json[ i ]; - var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.texturePath + image.url; + for ( var key in attributes ) { - images[ image.uuid ] = loadImage( path ); + var attribute = attributes[ key ]; + var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); - } + geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); } - return images; - - }, + var groups = json.data.groups || json.data.drawcalls || json.data.offsets; - parseTextures: function ( json, images ) { + if ( groups !== undefined ) { - function parseConstant( value, type ) { + for ( var i = 0, n = groups.length; i !== n; ++ i ) { - if ( typeof value === 'number' ) return value; + var group = groups[ i ]; - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + geometry.addGroup( group.start, group.count, group.materialIndex ); - return type[ value ]; + } } - var textures = {}; - - if ( json !== undefined ) { + var boundingSphere = json.data.boundingSphere; - for ( var i = 0, l = json.length; i < l; i ++ ) { + if ( boundingSphere !== undefined ) { - var data = json[ i ]; + var center = new Vector3(); - if ( data.image === undefined ) { + if ( boundingSphere.center !== undefined ) { - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); + center.fromArray( boundingSphere.center ); - } + } - if ( images[ data.image ] === undefined ) { + geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + } - } + return geometry; - var texture = new Texture( images[ data.image ] ); - texture.needsUpdate = true; + } - texture.uuid = data.uuid; +} ); - if ( data.name !== undefined ) texture.name = data.name; +var TYPED_ARRAYS = { + Int8Array: Int8Array, + Uint8Array: Uint8Array, + // Workaround for IE11 pre KB2929437. See #11440 + Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, + Int16Array: Int16Array, + Uint16Array: Uint16Array, + Int32Array: Int32Array, + Uint32Array: Uint32Array, + Float32Array: Float32Array, + Float64Array: Float64Array +}; - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); +/** + * @author alteredq / http://alteredqualia.com/ + */ - if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); - if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); - if ( data.center !== undefined ) texture.center.fromArray( data.center ); - if ( data.rotation !== undefined ) texture.rotation = data.rotation; +function Loader() { - if ( data.wrap !== undefined ) { + this.onLoadStart = function () {}; + this.onLoadProgress = function () {}; + this.onLoadComplete = function () {}; - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); +} - } +Loader.Handlers = { - if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); - if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); - if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; + handlers: [], - if ( data.flipY !== undefined ) texture.flipY = data.flipY; + add: function ( regex, loader ) { - textures[ data.uuid ] = texture; + this.handlers.push( regex, loader ); - } + }, - } + get: function ( file ) { - return textures; + var handlers = this.handlers; - }, + for ( var i = 0, l = handlers.length; i < l; i += 2 ) { - parseObject: function () { + var regex = handlers[ i ]; + var loader = handlers[ i + 1 ]; - var matrix = new Matrix4(); + if ( regex.test( file ) ) { - return function parseObject( data, geometries, materials ) { + return loader; - var object; + } - function getGeometry( name ) { + } - if ( geometries[ name ] === undefined ) { + return null; - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + } - } +}; - return geometries[ name ]; +Object.assign( Loader.prototype, { - } + crossOrigin: undefined, - function getMaterial( name ) { + initMaterials: function ( materials, texturePath, crossOrigin ) { - if ( name === undefined ) return undefined; + var array = []; - if ( Array.isArray( name ) ) { + for ( var i = 0; i < materials.length; ++ i ) { - var array = []; + array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); - for ( var i = 0, l = name.length; i < l; i ++ ) { + } - var uuid = name[ i ]; + return array; - if ( materials[ uuid ] === undefined ) { + }, - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + createMaterial: ( function () { - } + var BlendingMode = { + NoBlending: NoBlending, + NormalBlending: NormalBlending, + AdditiveBlending: AdditiveBlending, + SubtractiveBlending: SubtractiveBlending, + MultiplyBlending: MultiplyBlending, + CustomBlending: CustomBlending + }; - array.push( materials[ uuid ] ); + var color = new Color(); + var textureLoader = new TextureLoader(); + var materialLoader = new MaterialLoader(); - } + return function createMaterial( m, texturePath, crossOrigin ) { - return array; + // convert from old material format - } + var textures = {}; - if ( materials[ name ] === undefined ) { + function loadTexture( path, repeat, offset, wrap, anisotropy ) { - console.warn( 'THREE.ObjectLoader: Undefined material', name ); + var fullPath = texturePath + path; + var loader = Loader.Handlers.get( fullPath ); - } + var texture; - return materials[ name ]; + if ( loader !== null ) { - } + texture = loader.load( fullPath ); - switch ( data.type ) { + } else { - case 'Scene': + textureLoader.setCrossOrigin( crossOrigin ); + texture = textureLoader.load( fullPath ); - object = new Scene(); + } - if ( data.background !== undefined ) { + if ( repeat !== undefined ) { - if ( Number.isInteger( data.background ) ) { + texture.repeat.fromArray( repeat ); - object.background = new Color( data.background ); + if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; + if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; - } + } - } + if ( offset !== undefined ) { - if ( data.fog !== undefined ) { + texture.offset.fromArray( offset ); - if ( data.fog.type === 'Fog' ) { + } - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); + if ( wrap !== undefined ) { - } else if ( data.fog.type === 'FogExp2' ) { + if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; + if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; - object.fog = new FogExp2( data.fog.color, data.fog.density ); + if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; + if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; - } + } - } + if ( anisotropy !== undefined ) { - break; + texture.anisotropy = anisotropy; - case 'PerspectiveCamera': + } - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + var uuid = _Math.generateUUID(); - if ( data.focus !== undefined ) object.focus = data.focus; - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; - if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + textures[ uuid ] = texture; - break; + return uuid; - case 'OrthographicCamera': + } - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + // - break; + var json = { + uuid: _Math.generateUUID(), + type: 'MeshLambertMaterial' + }; - case 'AmbientLight': + for ( var name in m ) { - object = new AmbientLight( data.color, data.intensity ); + var value = m[ name ]; - break; + switch ( name ) { - case 'DirectionalLight': + case 'DbgColor': + case 'DbgIndex': + case 'opticalDensity': + case 'illumination': + break; + case 'DbgName': + json.name = value; + break; + case 'blending': + json.blending = BlendingMode[ value ]; + break; + case 'colorAmbient': + case 'mapAmbient': + console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); + break; + case 'colorDiffuse': + json.color = color.fromArray( value ).getHex(); + break; + case 'colorSpecular': + json.specular = color.fromArray( value ).getHex(); + break; + case 'colorEmissive': + json.emissive = color.fromArray( value ).getHex(); + break; + case 'specularCoef': + json.shininess = value; + break; + case 'shading': + if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; + if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; + if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; + break; + case 'mapDiffuse': + json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); + break; + case 'mapDiffuseRepeat': + case 'mapDiffuseOffset': + case 'mapDiffuseWrap': + case 'mapDiffuseAnisotropy': + break; + case 'mapEmissive': + json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); + break; + case 'mapEmissiveRepeat': + case 'mapEmissiveOffset': + case 'mapEmissiveWrap': + case 'mapEmissiveAnisotropy': + break; + case 'mapLight': + json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); + break; + case 'mapLightRepeat': + case 'mapLightOffset': + case 'mapLightWrap': + case 'mapLightAnisotropy': + break; + case 'mapAO': + json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); + break; + case 'mapAORepeat': + case 'mapAOOffset': + case 'mapAOWrap': + case 'mapAOAnisotropy': + break; + case 'mapBump': + json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); + break; + case 'mapBumpScale': + json.bumpScale = value; + break; + case 'mapBumpRepeat': + case 'mapBumpOffset': + case 'mapBumpWrap': + case 'mapBumpAnisotropy': + break; + case 'mapNormal': + json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); + break; + case 'mapNormalFactor': + json.normalScale = [ value, value ]; + break; + case 'mapNormalRepeat': + case 'mapNormalOffset': + case 'mapNormalWrap': + case 'mapNormalAnisotropy': + break; + case 'mapSpecular': + json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); + break; + case 'mapSpecularRepeat': + case 'mapSpecularOffset': + case 'mapSpecularWrap': + case 'mapSpecularAnisotropy': + break; + case 'mapMetalness': + json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); + break; + case 'mapMetalnessRepeat': + case 'mapMetalnessOffset': + case 'mapMetalnessWrap': + case 'mapMetalnessAnisotropy': + break; + case 'mapRoughness': + json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); + break; + case 'mapRoughnessRepeat': + case 'mapRoughnessOffset': + case 'mapRoughnessWrap': + case 'mapRoughnessAnisotropy': + break; + case 'mapAlpha': + json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); + break; + case 'mapAlphaRepeat': + case 'mapAlphaOffset': + case 'mapAlphaWrap': + case 'mapAlphaAnisotropy': + break; + case 'flipSided': + json.side = BackSide; + break; + case 'doubleSided': + json.side = DoubleSide; + break; + case 'transparency': + console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); + json.opacity = value; + break; + case 'depthTest': + case 'depthWrite': + case 'colorWrite': + case 'opacity': + case 'reflectivity': + case 'transparent': + case 'visible': + case 'wireframe': + json[ name ] = value; + break; + case 'vertexColors': + if ( value === true ) json.vertexColors = VertexColors; + if ( value === 'face' ) json.vertexColors = FaceColors; + break; + default: + console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); + break; - object = new DirectionalLight( data.color, data.intensity ); + } - break; + } - case 'PointLight': + if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; + if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); + if ( json.opacity < 1 ) json.transparent = true; - break; + materialLoader.setTextures( textures ); - case 'RectAreaLight': + return materialLoader.parse( json ); - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); + }; - break; + } )() - case 'SpotLight': +} ); - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); +/** + * @author Don McCurdy / https://www.donmccurdy.com + */ - break; +var LoaderUtils = { - case 'HemisphereLight': + decodeText: function ( array ) { - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); + if ( typeof TextDecoder !== 'undefined' ) { - break; + return new TextDecoder().decode( array ); - case 'SkinnedMesh': + } - console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); + // Avoid the String.fromCharCode.apply(null, array) shortcut, which + // throws a "maximum call stack size exceeded" error for large arrays. - case 'Mesh': + var s = ''; - var geometry = getGeometry( data.geometry ); - var material = getMaterial( data.material ); + for ( var i = 0, il = array.length; i < il; i ++ ) { - if ( geometry.bones && geometry.bones.length > 0 ) { + // Implicitly assumes little-endian. + s += String.fromCharCode( array[ i ] ); - object = new SkinnedMesh( geometry, material ); + } - } else { + return s; - object = new Mesh( geometry, material ); + }, - } + extractUrlBase: function ( url ) { - break; + var parts = url.split( '/' ); - case 'LOD': + if ( parts.length === 1 ) return './'; - object = new LOD(); + parts.pop(); - break; + return parts.join( '/' ) + '/'; - case 'Line': + } - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); +}; - break; +/** + * @author mrdoob / http://mrdoob.com/ + * @author alteredq / http://alteredqualia.com/ + */ - case 'LineLoop': +function JSONLoader( manager ) { - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); + if ( typeof manager === 'boolean' ) { - break; + console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); + manager = undefined; - case 'LineSegments': + } - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - break; + this.withCredentials = false; - case 'PointCloud': - case 'Points': +} - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); +Object.assign( JSONLoader.prototype, { - break; + load: function ( url, onLoad, onProgress, onError ) { - case 'Sprite': + var scope = this; - object = new Sprite( getMaterial( data.material ) ); + var texturePath = this.texturePath && ( typeof this.texturePath === 'string' ) ? this.texturePath : LoaderUtils.extractUrlBase( url ); - break; + var loader = new FileLoader( this.manager ); + loader.setWithCredentials( this.withCredentials ); + loader.load( url, function ( text ) { - case 'Group': + var json = JSON.parse( text ); + var metadata = json.metadata; - object = new Group(); + if ( metadata !== undefined ) { - break; + var type = metadata.type; - default: + if ( type !== undefined ) { - object = new Object3D(); + if ( type.toLowerCase() === 'object' ) { - } + console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); + return; - object.uuid = data.uuid; + } - if ( data.name !== undefined ) object.name = data.name; - if ( data.matrix !== undefined ) { + if ( type.toLowerCase() === 'scene' ) { - matrix.fromArray( data.matrix ); - matrix.decompose( object.position, object.quaternion, object.scale ); + console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.SceneLoader instead.' ); + return; - } else { + } - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); - if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); + } } - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + var object = scope.parse( json, texturePath ); + onLoad( object.geometry, object.materials ); - if ( data.shadow ) { + }, onProgress, onError ); - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); + }, - } + setTexturePath: function ( value ) { - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.userData !== undefined ) object.userData = data.userData; + this.texturePath = value; - if ( data.children !== undefined ) { + }, - var children = data.children; + parse: ( function () { - for ( var i = 0; i < children.length; i ++ ) { + function parseModel( json, geometry ) { - object.add( this.parseObject( children[ i ], geometries, materials ) ); + function isBitSet( value, position ) { - } + return value & ( 1 << position ); } - if ( data.type === 'LOD' ) { + var i, j, fi, - var levels = data.levels; + offset, zLength, - for ( var l = 0; l < levels.length; l ++ ) { + colorIndex, normalIndex, uvIndex, materialIndex, - var level = levels[ l ]; - var child = object.getObjectByProperty( 'uuid', level.object ); + type, + isQuad, + hasMaterial, + hasFaceVertexUv, + hasFaceNormal, hasFaceVertexNormal, + hasFaceColor, hasFaceVertexColor, - if ( child !== undefined ) { + vertex, face, faceA, faceB, hex, normal, - object.addLevel( child, level.distance ); + uvLayer, uv, u, v, - } + faces = json.faces, + vertices = json.vertices, + normals = json.normals, + colors = json.colors, - } + scale = json.scale, - } + nUvLayers = 0; - return object; - }; + if ( json.uvs !== undefined ) { - }() + // disregard empty arrays -} ); + for ( i = 0; i < json.uvs.length; i ++ ) { -var TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - SphericalReflectionMapping: SphericalReflectionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubeUVRefractionMapping: CubeUVRefractionMapping -}; + if ( json.uvs[ i ].length ) nUvLayers ++; -var TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping -}; + } -var TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipMapNearestFilter: NearestMipMapNearestFilter, - NearestMipMapLinearFilter: NearestMipMapLinearFilter, - LinearFilter: LinearFilter, - LinearMipMapNearestFilter: LinearMipMapNearestFilter, - LinearMipMapLinearFilter: LinearMipMapLinearFilter -}; + for ( i = 0; i < nUvLayers; i ++ ) { + + geometry.faceVertexUvs[ i ] = []; -/** - * @author thespite / http://clicktorelease.com/ - */ + } -function ImageBitmapLoader( manager ) { + } - if ( typeof createImageBitmap === 'undefined' ) { + offset = 0; + zLength = vertices.length; - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); + while ( offset < zLength ) { - } + vertex = new Vector3(); - if ( typeof fetch === 'undefined' ) { + vertex.x = vertices[ offset ++ ] * scale; + vertex.y = vertices[ offset ++ ] * scale; + vertex.z = vertices[ offset ++ ] * scale; - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); + geometry.vertices.push( vertex ); - } + } - this.manager = manager !== undefined ? manager : DefaultLoadingManager; - this.options = undefined; + offset = 0; + zLength = faces.length; -} + while ( offset < zLength ) { -ImageBitmapLoader.prototype = { + type = faces[ offset ++ ]; - constructor: ImageBitmapLoader, + isQuad = isBitSet( type, 0 ); + hasMaterial = isBitSet( type, 1 ); + hasFaceVertexUv = isBitSet( type, 3 ); + hasFaceNormal = isBitSet( type, 4 ); + hasFaceVertexNormal = isBitSet( type, 5 ); + hasFaceColor = isBitSet( type, 6 ); + hasFaceVertexColor = isBitSet( type, 7 ); - setOptions: function setOptions( options ) { + // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); - this.options = options; + if ( isQuad ) { - return this; + faceA = new Face3(); + faceA.a = faces[ offset ]; + faceA.b = faces[ offset + 1 ]; + faceA.c = faces[ offset + 3 ]; - }, + faceB = new Face3(); + faceB.a = faces[ offset + 1 ]; + faceB.b = faces[ offset + 2 ]; + faceB.c = faces[ offset + 3 ]; - load: function load( url, onLoad, onProgress, onError ) { + offset += 4; - if ( url === undefined ) url = ''; + if ( hasMaterial ) { - if ( this.path !== undefined ) url = this.path + url; + materialIndex = faces[ offset ++ ]; + faceA.materialIndex = materialIndex; + faceB.materialIndex = materialIndex; - var scope = this; + } - var cached = Cache.get( url ); + // to get face <=> uv index correspondence - if ( cached !== undefined ) { + fi = geometry.faces.length; - scope.manager.itemStart( url ); + if ( hasFaceVertexUv ) { - setTimeout( function () { + for ( i = 0; i < nUvLayers; i ++ ) { - if ( onLoad ) onLoad( cached ); + uvLayer = json.uvs[ i ]; - scope.manager.itemEnd( url ); + geometry.faceVertexUvs[ i ][ fi ] = []; + geometry.faceVertexUvs[ i ][ fi + 1 ] = []; - }, 0 ); + for ( j = 0; j < 4; j ++ ) { - return cached; + uvIndex = faces[ offset ++ ]; - } + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; - fetch( url ).then( function ( res ) { + uv = new Vector2( u, v ); - return res.blob(); + if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); + if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); - } ).then( function ( blob ) { + } - return createImageBitmap( blob, scope.options ); + } - } ).then( function ( imageBitmap ) { + } - Cache.add( url, imageBitmap ); + if ( hasFaceNormal ) { - if ( onLoad ) onLoad( imageBitmap ); + normalIndex = faces[ offset ++ ] * 3; - scope.manager.itemEnd( url ); + faceA.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - } ).catch( function ( e ) { + faceB.normal.copy( faceA.normal ); - if ( onError ) onError( e ); + } - scope.manager.itemEnd( url ); - scope.manager.itemError( url ); + if ( hasFaceVertexNormal ) { - } ); + for ( i = 0; i < 4; i ++ ) { - }, + normalIndex = faces[ offset ++ ] * 3; - setCrossOrigin: function ( /* value */ ) { + normal = new Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); - return this; - }, + if ( i !== 2 ) faceA.vertexNormals.push( normal ); + if ( i !== 0 ) faceB.vertexNormals.push( normal ); - setPath: function ( value ) { + } - this.path = value; - return this; + } - } -}; + if ( hasFaceColor ) { -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Bezier Curves formulas obtained from - * http://en.wikipedia.org/wiki/Bézier_curve - */ + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; -function CatmullRom( t, p0, p1, p2, p3 ) { + faceA.color.setHex( hex ); + faceB.color.setHex( hex ); - var v0 = ( p2 - p0 ) * 0.5; - var v1 = ( p3 - p1 ) * 0.5; - var t2 = t * t; - var t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + } -} -// + if ( hasFaceVertexColor ) { -function QuadraticBezierP0( t, p ) { + for ( i = 0; i < 4; i ++ ) { - var k = 1 - t; - return k * k * p; + colorIndex = faces[ offset ++ ]; + hex = colors[ colorIndex ]; -} + if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); + if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); -function QuadraticBezierP1( t, p ) { + } - return 2 * ( 1 - t ) * t * p; + } -} + geometry.faces.push( faceA ); + geometry.faces.push( faceB ); -function QuadraticBezierP2( t, p ) { + } else { - return t * t * p; + face = new Face3(); + face.a = faces[ offset ++ ]; + face.b = faces[ offset ++ ]; + face.c = faces[ offset ++ ]; -} + if ( hasMaterial ) { -function QuadraticBezier( t, p0, p1, p2 ) { + materialIndex = faces[ offset ++ ]; + face.materialIndex = materialIndex; - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); + } -} + // to get face <=> uv index correspondence -// + fi = geometry.faces.length; -function CubicBezierP0( t, p ) { + if ( hasFaceVertexUv ) { - var k = 1 - t; - return k * k * k * p; + for ( i = 0; i < nUvLayers; i ++ ) { -} + uvLayer = json.uvs[ i ]; -function CubicBezierP1( t, p ) { + geometry.faceVertexUvs[ i ][ fi ] = []; - var k = 1 - t; - return 3 * k * k * t * p; + for ( j = 0; j < 3; j ++ ) { -} + uvIndex = faces[ offset ++ ]; -function CubicBezierP2( t, p ) { + u = uvLayer[ uvIndex * 2 ]; + v = uvLayer[ uvIndex * 2 + 1 ]; - return 3 * ( 1 - t ) * t * t * p; + uv = new Vector2( u, v ); -} + geometry.faceVertexUvs[ i ][ fi ].push( uv ); -function CubicBezierP3( t, p ) { + } - return t * t * t * p; + } -} + } -function CubicBezier( t, p0, p1, p2, p3 ) { + if ( hasFaceNormal ) { - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); + normalIndex = faces[ offset ++ ] * 3; -} + face.normal.set( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object - * - * Some common of curve methods: - * .getPoint( t, optionalTarget ), .getTangent( t ) - * .getPointAt( u, optionalTarget ), .getTangentAt( u ) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following curves inherit from THREE.Curve: - * - * -- 2D curves -- - * THREE.ArcCurve - * THREE.CubicBezierCurve - * THREE.EllipseCurve - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.SplineCurve - * - * -- 3D curves -- - * THREE.CatmullRomCurve3 - * THREE.CubicBezierCurve3 - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * - * A series of curves can be represented as a THREE.CurvePath. - * - **/ + } -/************************************************************** - * Abstract Curve base class - **************************************************************/ + if ( hasFaceVertexNormal ) { -function Curve() { + for ( i = 0; i < 3; i ++ ) { - this.type = 'Curve'; + normalIndex = faces[ offset ++ ] * 3; - this.arcLengthDivisions = 200; + normal = new Vector3( + normals[ normalIndex ++ ], + normals[ normalIndex ++ ], + normals[ normalIndex ] + ); -} + face.vertexNormals.push( normal ); -Object.assign( Curve.prototype, { + } - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] + } - getPoint: function ( /* t, optionalTarget */ ) { - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; + if ( hasFaceColor ) { - }, + colorIndex = faces[ offset ++ ]; + face.color.setHex( colors[ colorIndex ] ); - // Get point at relative position in curve according to arc length - // - u [0 .. 1] + } - getPointAt: function ( u, optionalTarget ) { - var t = this.getUtoTmapping( u ); - return this.getPoint( t, optionalTarget ); + if ( hasFaceVertexColor ) { - }, + for ( i = 0; i < 3; i ++ ) { - // Get sequence of points using getPoint( t ) + colorIndex = faces[ offset ++ ]; + face.vertexColors.push( new Color( colors[ colorIndex ] ) ); - getPoints: function ( divisions ) { + } - if ( divisions === undefined ) divisions = 5; + } - var points = []; + geometry.faces.push( face ); - for ( var d = 0; d <= divisions; d ++ ) { + } - points.push( this.getPoint( d / divisions ) ); + } } - return points; + function parseSkin( json, geometry ) { - }, + var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; - // Get sequence of points using getPointAt( u ) + if ( json.skinWeights ) { - getSpacedPoints: function ( divisions ) { + for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { - if ( divisions === undefined ) divisions = 5; + var x = json.skinWeights[ i ]; + var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; + var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; + var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; - var points = []; + geometry.skinWeights.push( new Vector4( x, y, z, w ) ); - for ( var d = 0; d <= divisions; d ++ ) { + } - points.push( this.getPointAt( d / divisions ) ); + } - } + if ( json.skinIndices ) { - return points; + for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { - }, + var a = json.skinIndices[ i ]; + var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; + var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; + var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; - // Get total curve arc length + geometry.skinIndices.push( new Vector4( a, b, c, d ) ); - getLength: function () { + } - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; + } - }, + geometry.bones = json.bones; - // Get list of cumulative segment lengths + if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { - getLengths: function ( divisions ) { + console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); - if ( divisions === undefined ) divisions = this.arcLengthDivisions; + } - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { + } - return this.cacheArcLengths; + function parseMorphing( json, geometry ) { - } + var scale = json.scale; - this.needsUpdate = false; + if ( json.morphTargets !== undefined ) { - var cache = []; - var current, last = this.getPoint( 0 ); - var p, sum = 0; + for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { - cache.push( 0 ); + geometry.morphTargets[ i ] = {}; + geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; + geometry.morphTargets[ i ].vertices = []; - for ( p = 1; p <= divisions; p ++ ) { + var dstVertices = geometry.morphTargets[ i ].vertices; + var srcVertices = json.morphTargets[ i ].vertices; - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; + for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { - } + var vertex = new Vector3(); + vertex.x = srcVertices[ v ] * scale; + vertex.y = srcVertices[ v + 1 ] * scale; + vertex.z = srcVertices[ v + 2 ] * scale; - this.cacheArcLengths = cache; + dstVertices.push( vertex ); - return cache; // { sums: cache, sum: sum }; Sum is in the last element. + } - }, + } - updateArcLengths: function () { + } - this.needsUpdate = true; - this.getLengths(); + if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { - }, + console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant + var faces = geometry.faces; + var morphColors = json.morphColors[ 0 ].colors; - getUtoTmapping: function ( u, distance ) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - var arcLengths = this.getLengths(); + faces[ i ].color.fromArray( morphColors, i * 3 ); - var i = 0, il = arcLengths.length; + } - var targetArcLength; // The targeted u distance value to get + } - if ( distance ) { + } - targetArcLength = distance; + function parseAnimations( json, geometry ) { - } else { + var outputAnimations = []; - targetArcLength = u * arcLengths[ il - 1 ]; + // parse old style Bone/Hierarchy animations + var animations = []; - } + if ( json.animation !== undefined ) { - // binary search for the index with largest value smaller than target u distance + animations.push( json.animation ); - var low = 0, high = il - 1, comparison; + } - while ( low <= high ) { + if ( json.animations !== undefined ) { - i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats + if ( json.animations.length ) { - comparison = arcLengths[ i ] - targetArcLength; + animations = animations.concat( json.animations ); - if ( comparison < 0 ) { + } else { - low = i + 1; + animations.push( json.animations ); - } else if ( comparison > 0 ) { + } - high = i - 1; + } - } else { + for ( var i = 0; i < animations.length; i ++ ) { - high = i; - break; + var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); + if ( clip ) outputAnimations.push( clip ); - // DONE + } + + // parse implicit morph animations + if ( geometry.morphTargets ) { + + // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. + var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); + outputAnimations = outputAnimations.concat( morphAnimationClips ); } + if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; + } - i = high; + return function ( json, texturePath ) { - if ( arcLengths[ i ] === targetArcLength ) { + if ( json.data !== undefined ) { - return i / ( il - 1 ); + // Geometry 4.0 spec + json = json.data; - } + } - // we could get finer grain at lengths, or use simple interpolation between two points + if ( json.scale !== undefined ) { - var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; + json.scale = 1.0 / json.scale; - var segmentLength = lengthAfter - lengthBefore; + } else { - // determine where we are between the 'before' and 'after' points + json.scale = 1.0; - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + } - // add that fractional amount to t + var geometry = new Geometry(); - var t = ( i + segmentFraction ) / ( il - 1 ); + parseModel( json, geometry ); + parseSkin( json, geometry ); + parseMorphing( json, geometry ); + parseAnimations( json, geometry ); - return t; + geometry.computeFaceNormals(); + geometry.computeBoundingSphere(); - }, + if ( json.materials === undefined || json.materials.length === 0 ) { - // Returns a unit vector tangent at t - // In case any sub curve does not implement its tangent derivation, - // 2 points a small delta apart will be used to find its gradient - // which seems to give a reasonable approximation + return { geometry: geometry }; - getTangent: function ( t ) { + } else { - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; + var materials = Loader.prototype.initMaterials( json.materials, texturePath, this.crossOrigin ); - // Capping in case of danger + return { geometry: geometry, materials: materials }; - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; + } - var pt1 = this.getPoint( t1 ); - var pt2 = this.getPoint( t2 ); + }; + + } )() + +} ); + +/** + * @author mrdoob / http://mrdoob.com/ + */ + +function ObjectLoader( manager ) { - var vec = pt2.clone().sub( pt1 ); - return vec.normalize(); + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.texturePath = ''; - }, +} - getTangentAt: function ( u ) { +Object.assign( ObjectLoader.prototype, { - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); + load: function ( url, onLoad, onProgress, onError ) { - }, + if ( this.texturePath === '' ) { - computeFrenetFrames: function ( segments, closed ) { + this.texturePath = url.substring( 0, url.lastIndexOf( '/' ) + 1 ); - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + } - var normal = new Vector3(); + var scope = this; - var tangents = []; - var normals = []; - var binormals = []; + var loader = new FileLoader( scope.manager ); + loader.load( url, function ( text ) { - var vec = new Vector3(); - var mat = new Matrix4(); + var json = null; - var i, u, theta; + try { - // compute the tangent vectors for each segment on the curve + json = JSON.parse( text ); - for ( i = 0; i <= segments; i ++ ) { + } catch ( error ) { - u = i / segments; + if ( onError !== undefined ) onError( error ); - tangents[ i ] = this.getTangentAt( u ); - tangents[ i ].normalize(); + console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - } + return; - // select an initial normal vector perpendicular to the first tangent vector, - // and in the direction of the minimum tangent xyz component + } - normals[ 0 ] = new Vector3(); - binormals[ 0 ] = new Vector3(); - var min = Number.MAX_VALUE; - var tx = Math.abs( tangents[ 0 ].x ); - var ty = Math.abs( tangents[ 0 ].y ); - var tz = Math.abs( tangents[ 0 ].z ); + var metadata = json.metadata; - if ( tx <= min ) { + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - min = tx; - normal.set( 1, 0, 0 ); + console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); + return; - } + } - if ( ty <= min ) { + scope.parse( json, onLoad ); - min = ty; - normal.set( 0, 1, 0 ); + }, onProgress, onError ); - } + }, - if ( tz <= min ) { + setTexturePath: function ( value ) { - normal.set( 0, 0, 1 ); + this.texturePath = value; - } + }, - vec.crossVectors( tangents[ 0 ], normal ).normalize(); + setCrossOrigin: function ( value ) { - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + this.crossOrigin = value; + }, - // compute the slowly-varying normal and binormal vectors for each segment on the curve + parse: function ( json, onLoad ) { - for ( i = 1; i <= segments; i ++ ) { + var shapes = this.parseShape( json.shapes ); + var geometries = this.parseGeometries( json.geometries, shapes ); - normals[ i ] = normals[ i - 1 ].clone(); + var images = this.parseImages( json.images, function () { - binormals[ i ] = binormals[ i - 1 ].clone(); + if ( onLoad !== undefined ) onLoad( object ); - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); + } ); - if ( vec.length() > Number.EPSILON ) { + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); - vec.normalize(); + var object = this.parseObject( json.object, geometries, materials ); - theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors + if ( json.animations ) { - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + object.animations = this.parseAnimations( json.animations ); - } + } - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + if ( json.images === undefined || json.images.length === 0 ) { + + if ( onLoad !== undefined ) onLoad( object ); } - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + return object; - if ( closed === true ) { + }, - theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; + parseShape: function ( json ) { - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { + var shapes = {}; - theta = - theta; + if ( json !== undefined ) { - } + for ( var i = 0, l = json.length; i < l; i ++ ) { - for ( i = 1; i <= segments; i ++ ) { + var shape = new Shape().fromJSON( json[ i ] ); - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + shapes[ shape.uuid ] = shape; } } - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; + return shapes; }, - clone: function () { - - return new this.constructor().copy( this ); + parseGeometries: function ( json, shapes ) { - }, + var geometries = {}; - copy: function ( source ) { + if ( json !== undefined ) { - this.arcLengthDivisions = source.arcLengthDivisions; + var geometryLoader = new JSONLoader(); + var bufferGeometryLoader = new BufferGeometryLoader(); - return this; + for ( var i = 0, l = json.length; i < l; i ++ ) { - } + var geometry; + var data = json[ i ]; -} ); + switch ( data.type ) { -function LineCurve( v1, v2 ) { + case 'PlaneGeometry': + case 'PlaneBufferGeometry': - Curve.call( this ); + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); - this.type = 'LineCurve'; + break; - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); + case 'BoxGeometry': + case 'BoxBufferGeometry': + case 'CubeGeometry': // backwards compatible -} + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); -LineCurve.prototype = Object.create( Curve.prototype ); -LineCurve.prototype.constructor = LineCurve; + break; -LineCurve.prototype.isLineCurve = true; + case 'CircleGeometry': + case 'CircleBufferGeometry': -LineCurve.prototype.getPoint = function ( t, optionalTarget ) { + geometry = new Geometries[ data.type ]( + data.radius, + data.segments, + data.thetaStart, + data.thetaLength + ); - var point = optionalTarget || new Vector2(); + break; - if ( t === 1 ) { + case 'CylinderGeometry': + case 'CylinderBufferGeometry': - point.copy( this.v2 ); + geometry = new Geometries[ data.type ]( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); - } else { + break; - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); + case 'ConeGeometry': + case 'ConeBufferGeometry': - } + geometry = new Geometries[ data.type ]( + data.radius, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); - return point; + break; -}; + case 'SphereGeometry': + case 'SphereBufferGeometry': -// Line curve is linear, so we can overwrite default getPointAt + geometry = new Geometries[ data.type ]( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); -LineCurve.prototype.getPointAt = function ( u, optionalTarget ) { + break; - return this.getPoint( u, optionalTarget ); + case 'DodecahedronGeometry': + case 'DodecahedronBufferGeometry': + case 'IcosahedronGeometry': + case 'IcosahedronBufferGeometry': + case 'OctahedronGeometry': + case 'OctahedronBufferGeometry': + case 'TetrahedronGeometry': + case 'TetrahedronBufferGeometry': -}; + geometry = new Geometries[ data.type ]( + data.radius, + data.detail + ); -LineCurve.prototype.getTangent = function ( /* t */ ) { + break; - var tangent = this.v2.clone().sub( this.v1 ); + case 'RingGeometry': + case 'RingBufferGeometry': - return tangent.normalize(); + geometry = new Geometries[ data.type ]( + data.innerRadius, + data.outerRadius, + data.thetaSegments, + data.phiSegments, + data.thetaStart, + data.thetaLength + ); -}; + break; -LineCurve.prototype.copy = function ( source ) { + case 'TorusGeometry': + case 'TorusBufferGeometry': - Curve.prototype.copy.call( this, source ); + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + break; - return this; + case 'TorusKnotGeometry': + case 'TorusKnotBufferGeometry': -}; + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.tubularSegments, + data.radialSegments, + data.p, + data.q + ); -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - **/ + break; -/************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ + case 'LatheGeometry': + case 'LatheBufferGeometry': -function CurvePath() { + geometry = new Geometries[ data.type ]( + data.points, + data.segments, + data.phiStart, + data.phiLength + ); - Curve.call( this ); + break; - this.type = 'CurvePath'; + case 'PolyhedronGeometry': + case 'PolyhedronBufferGeometry': - this.curves = []; - this.autoClose = false; // Automatically closes the path + geometry = new Geometries[ data.type ]( + data.vertices, + data.indices, + data.radius, + data.details + ); -} + break; -CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { + case 'ShapeGeometry': + case 'ShapeBufferGeometry': - constructor: CurvePath, + var geometryShapes = []; - add: function ( curve ) { + for ( var i = 0, l = data.shapes.length; i < l; i ++ ) { - this.curves.push( curve ); + var shape = shapes[ data.shapes[ i ] ]; - }, + geometryShapes.push( shape ); - closePath: function () { + } - // 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 ); + geometry = new Geometries[ data.type ]( + geometryShapes, + data.curveSegments + ); - if ( ! startPoint.equals( endPoint ) ) { + break; - this.curves.push( new LineCurve( endPoint, startPoint ) ); + case 'BufferGeometry': - } + geometry = bufferGeometryLoader.parse( data ); - }, + break; - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: + case 'Geometry': - // 1. Length of each sub path have to be known - // 2. Locate and identify type of curve - // 3. Get t for the curve - // 4. Return curve.getPointAt(t') + geometry = geometryLoader.parse( data, this.texturePath ).geometry; - getPoint: function ( t ) { + break; - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0; + default: - // To think about boundaries points. + console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); - while ( i < curveLengths.length ) { + continue; - if ( curveLengths[ i ] >= d ) { + } - var diff = curveLengths[ i ] - d; - var curve = this.curves[ i ]; + geometry.uuid = data.uuid; - var segmentLength = curve.getLength(); - var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + if ( data.name !== undefined ) geometry.name = data.name; - return curve.getPointAt( u ); + geometries[ data.uuid ] = geometry; } - i ++; - } - return null; - - // loop where sum != 0, sum > d , sum+1 0 ) { - if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates + var manager = new LoadingManager( onLoad ); - points.push( point ); - last = point; + var loader = new ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); - } + 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; - if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { + images[ image.uuid ] = loadImage( path ); - points.push( points[ 0 ] ); + } } - return points; + return images; }, - copy: function ( source ) { - - Curve.prototype.copy.call( this, source ); + parseTextures: function ( json, images ) { - this.curves = []; + function parseConstant( value, type ) { - for ( var i = 0, l = source.curves.length; i < l; i ++ ) { + if ( typeof value === 'number' ) return value; - var curve = source.curves[ i ]; + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); - this.curves.push( curve.clone() ); + return type[ value ]; } - this.autoClose = source.autoClose; + var textures = {}; - return this; + if ( json !== undefined ) { - } + for ( var i = 0, l = json.length; i < l; i ++ ) { -} ); + var data = json[ i ]; -function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + if ( data.image === undefined ) { - Curve.call( this ); + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - this.type = 'EllipseCurve'; + } - this.aX = aX || 0; - this.aY = aY || 0; + if ( images[ data.image ] === undefined ) { - this.xRadius = xRadius || 1; - this.yRadius = yRadius || 1; + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + + } - this.aStartAngle = aStartAngle || 0; - this.aEndAngle = aEndAngle || 2 * Math.PI; + var texture = new Texture( images[ data.image ] ); + texture.needsUpdate = true; - this.aClockwise = aClockwise || false; + texture.uuid = data.uuid; - this.aRotation = aRotation || 0; + if ( data.name !== undefined ) texture.name = data.name; -} + if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); -EllipseCurve.prototype = Object.create( Curve.prototype ); -EllipseCurve.prototype.constructor = EllipseCurve; + if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); + if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); + if ( data.center !== undefined ) texture.center.fromArray( data.center ); + if ( data.rotation !== undefined ) texture.rotation = data.rotation; -EllipseCurve.prototype.isEllipseCurve = true; + if ( data.wrap !== undefined ) { -EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) { + texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - var point = optionalTarget || new Vector2(); + } - var twoPi = Math.PI * 2; - var deltaAngle = this.aEndAngle - this.aStartAngle; - var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); + if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); + if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; + if ( data.flipY !== undefined ) texture.flipY = data.flipY; - if ( deltaAngle < Number.EPSILON ) { + textures[ data.uuid ] = texture; - if ( samePoints ) { + } - deltaAngle = 0; + } - } else { + return textures; - deltaAngle = twoPi; + }, - } + parseObject: function () { - } + var matrix = new Matrix4(); - if ( this.aClockwise === true && ! samePoints ) { + return function parseObject( data, geometries, materials ) { - if ( deltaAngle === twoPi ) { + var object; - deltaAngle = - twoPi; + function getGeometry( name ) { - } else { + if ( geometries[ name ] === undefined ) { - deltaAngle = deltaAngle - twoPi; + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - } + } - } + return geometries[ name ]; - var angle = this.aStartAngle + t * deltaAngle; - var x = this.aX + this.xRadius * Math.cos( angle ); - var y = this.aY + this.yRadius * Math.sin( angle ); + } - if ( this.aRotation !== 0 ) { + function getMaterial( name ) { - var cos = Math.cos( this.aRotation ); - var sin = Math.sin( this.aRotation ); + if ( name === undefined ) return undefined; - var tx = x - this.aX; - var ty = y - this.aY; + if ( Array.isArray( name ) ) { - // Rotate the point about the center of the ellipse. - x = tx * cos - ty * sin + this.aX; - y = tx * sin + ty * cos + this.aY; + var array = []; - } + for ( var i = 0, l = name.length; i < l; i ++ ) { - return point.set( x, y ); + var uuid = name[ i ]; -}; + if ( materials[ uuid ] === undefined ) { -EllipseCurve.prototype.copy = function ( source ) { + console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); - Curve.prototype.copy.call( this, source ); + } - this.aX = source.aX; - this.aY = source.aY; + array.push( materials[ uuid ] ); - this.xRadius = source.xRadius; - this.yRadius = source.yRadius; + } - this.aStartAngle = source.aStartAngle; - this.aEndAngle = source.aEndAngle; + return array; - this.aClockwise = source.aClockwise; + } - this.aRotation = source.aRotation; + if ( materials[ name ] === undefined ) { - return this; + console.warn( 'THREE.ObjectLoader: Undefined material', name ); -}; + } -function SplineCurve( points /* array of Vector2 */ ) { + return materials[ name ]; - Curve.call( this ); + } - this.type = 'SplineCurve'; + switch ( data.type ) { - this.points = points || []; + case 'Scene': -} + object = new Scene(); -SplineCurve.prototype = Object.create( Curve.prototype ); -SplineCurve.prototype.constructor = SplineCurve; + if ( data.background !== undefined ) { -SplineCurve.prototype.isSplineCurve = true; + if ( Number.isInteger( data.background ) ) { -SplineCurve.prototype.getPoint = function ( t, optionalTarget ) { + object.background = new Color( data.background ); - var point = optionalTarget || new Vector2(); + } - var points = this.points; - var p = ( points.length - 1 ) * t; + } - var intPoint = Math.floor( p ); - var weight = p - intPoint; + if ( data.fog !== undefined ) { - var p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; - var p1 = points[ intPoint ]; - var p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; - var p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; + if ( data.fog.type === 'Fog' ) { - point.set( - CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), - CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) - ); + object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - return point; + } else if ( data.fog.type === 'FogExp2' ) { -}; + object.fog = new FogExp2( data.fog.color, data.fog.density ); -SplineCurve.prototype.copy = function ( source ) { + } - Curve.prototype.copy.call( this, source ); + } - this.points = []; + break; - for ( var i = 0, l = source.points.length; i < l; i ++ ) { + case 'PerspectiveCamera': - var point = source.points[ i ]; + object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - this.points.push( point.clone() ); + if ( data.focus !== undefined ) object.focus = data.focus; + if ( data.zoom !== undefined ) object.zoom = data.zoom; + if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; + if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; + if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - } + break; - return this; + case 'OrthographicCamera': -}; + object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); -function CubicBezierCurve( v0, v1, v2, v3 ) { + break; - Curve.call( this ); + case 'AmbientLight': - this.type = 'CubicBezierCurve'; + object = new AmbientLight( data.color, data.intensity ); - this.v0 = v0 || new Vector2(); - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); - this.v3 = v3 || new Vector2(); + break; -} + case 'DirectionalLight': -CubicBezierCurve.prototype = Object.create( Curve.prototype ); -CubicBezierCurve.prototype.constructor = CubicBezierCurve; + object = new DirectionalLight( data.color, data.intensity ); -CubicBezierCurve.prototype.isCubicBezierCurve = true; + break; -CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { + case 'PointLight': - var point = optionalTarget || new Vector2(); + object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + break; - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) - ); + case 'RectAreaLight': - return point; + object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); -}; + break; -CubicBezierCurve.prototype.copy = function ( source ) { + case 'SpotLight': - Curve.prototype.copy.call( this, source ); + object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); + break; - return this; + case 'HemisphereLight': -}; + object = new HemisphereLight( data.color, data.groundColor, data.intensity ); -function QuadraticBezierCurve( v0, v1, v2 ) { + break; - Curve.call( this ); + case 'SkinnedMesh': - this.type = 'QuadraticBezierCurve'; + console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); - this.v0 = v0 || new Vector2(); - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); + case 'Mesh': -} + var geometry = getGeometry( data.geometry ); + var material = getMaterial( data.material ); -QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); -QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; + if ( geometry.bones && geometry.bones.length > 0 ) { -QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; + object = new SkinnedMesh( geometry, material ); -QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { + } else { - var point = optionalTarget || new Vector2(); + object = new Mesh( geometry, material ); - var v0 = this.v0, v1 = this.v1, v2 = this.v2; + } - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ) - ); + break; - return point; + case 'LOD': -}; + object = new LOD(); -QuadraticBezierCurve.prototype.copy = function ( source ) { + break; - Curve.prototype.copy.call( this, source ); + case 'Line': - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - return this; + break; -}; + case 'LineLoop': -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. - **/ + object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); -function Path( points ) { + break; - CurvePath.call( this ); + case 'LineSegments': - this.type = 'Path'; + object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - this.currentPoint = new Vector2(); + break; - if ( points ) { + case 'PointCloud': + case 'Points': - this.setFromPoints( points ); + object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - } + break; -} + case 'Sprite': -Path.prototype = Object.assign( Object.create( CurvePath.prototype ), { + object = new Sprite( getMaterial( data.material ) ); - constructor: Path, + break; - setFromPoints: function ( points ) { + case 'Group': - this.moveTo( points[ 0 ].x, points[ 0 ].y ); + object = new Group(); - for ( var i = 1, l = points.length; i < l; i ++ ) { + break; - this.lineTo( points[ i ].x, points[ i ].y ); + default: - } + object = new Object3D(); - }, + } - moveTo: function ( x, y ) { + object.uuid = data.uuid; - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? + if ( data.name !== undefined ) object.name = data.name; + if ( data.matrix !== undefined ) { - }, + matrix.fromArray( data.matrix ); + matrix.decompose( object.position, object.quaternion, object.scale ); - lineTo: function ( x, y ) { + } else { - var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); + if ( data.position !== undefined ) object.position.fromArray( data.position ); + if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); + if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); + if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); - this.currentPoint.set( x, y ); + } - }, + if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; + if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; - quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + if ( data.shadow ) { - var curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); + if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; + if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; + if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); + if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); - this.curves.push( curve ); + } - this.currentPoint.set( aX, aY ); + if ( data.visible !== undefined ) object.visible = data.visible; + if ( data.userData !== undefined ) object.userData = data.userData; - }, + if ( data.children !== undefined ) { - bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + var children = data.children; - var curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); + for ( var i = 0; i < children.length; i ++ ) { - this.curves.push( curve ); + object.add( this.parseObject( children[ i ], geometries, materials ) ); - this.currentPoint.set( aX, aY ); + } - }, + } - splineThru: function ( pts /*Array of Vector*/ ) { + if ( data.type === 'LOD' ) { - var npts = [ this.currentPoint.clone() ].concat( pts ); + var levels = data.levels; - var curve = new SplineCurve( npts ); - this.curves.push( curve ); + for ( var l = 0; l < levels.length; l ++ ) { - this.currentPoint.copy( pts[ pts.length - 1 ] ); + var level = levels[ l ]; + var child = object.getObjectByProperty( 'uuid', level.object ); - }, + if ( child !== undefined ) { - arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + object.addLevel( child, level.distance ); - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; + } - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); + } - }, + } - absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + return object; - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + }; - }, + }() - ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { +} ); - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; +var TEXTURE_MAPPING = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + SphericalReflectionMapping: SphericalReflectionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping, + CubeUVRefractionMapping: CubeUVRefractionMapping +}; - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); +var TEXTURE_WRAPPING = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping +}; - }, +var TEXTURE_FILTER = { + NearestFilter: NearestFilter, + NearestMipMapNearestFilter: NearestMipMapNearestFilter, + NearestMipMapLinearFilter: NearestMipMapLinearFilter, + LinearFilter: LinearFilter, + LinearMipMapNearestFilter: LinearMipMapNearestFilter, + LinearMipMapLinearFilter: LinearMipMapLinearFilter +}; - absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { +/** + * @author thespite / http://clicktorelease.com/ + */ - var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); +function ImageBitmapLoader( manager ) { - if ( this.curves.length > 0 ) { + if ( typeof createImageBitmap === 'undefined' ) { - // if a previous curve is present, attempt to join - var firstPoint = curve.getPoint( 0 ); + console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - if ( ! firstPoint.equals( this.currentPoint ) ) { + } - this.lineTo( firstPoint.x, firstPoint.y ); + if ( typeof fetch === 'undefined' ) { - } + console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - } + } - this.curves.push( curve ); + this.manager = manager !== undefined ? manager : DefaultLoadingManager; + this.options = undefined; - var lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); +} - }, +ImageBitmapLoader.prototype = { - copy: function ( source ) { + constructor: ImageBitmapLoader, - CurvePath.prototype.copy.call( this, source ); + setOptions: function setOptions( options ) { - this.currentPoint.copy( source.currentPoint ); + this.options = options; return this; - } + }, -} ); + load: function load( url, onLoad, onProgress, onError ) { -/** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Defines a 2d shape plane using paths. - **/ + if ( url === undefined ) url = ''; -// STEP 1 Create a path. -// STEP 2 Turn path into shape. -// STEP 3 ExtrudeGeometry takes in Shape/Shapes -// STEP 3a - Extract points from each shape, turn to vertices -// STEP 3b - Triangulate each shape, add faces. + if ( this.path !== undefined ) url = this.path + url; -function Shape( points ) { + var scope = this; - Path.call( this, points ); + var cached = Cache.get( url ); - this.type = 'Shape'; + if ( cached !== undefined ) { - this.holes = []; + scope.manager.itemStart( url ); -} + setTimeout( function () { -Shape.prototype = Object.assign( Object.create( Path.prototype ), { + if ( onLoad ) onLoad( cached ); - constructor: Shape, + scope.manager.itemEnd( url ); - getPointsHoles: function ( divisions ) { + }, 0 ); - var holesPts = []; + return cached; - for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + } - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); + fetch( url ).then( function ( res ) { - } + return res.blob(); - return holesPts; + } ).then( function ( blob ) { - }, + return createImageBitmap( blob, scope.options ); - // get points of shape and holes (keypoints based on segments parameter) + } ).then( function ( imageBitmap ) { - extractPoints: function ( divisions ) { + Cache.add( url, imageBitmap ); - return { + if ( onLoad ) onLoad( imageBitmap ); - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) + scope.manager.itemEnd( url ); - }; + } ).catch( function ( e ) { - }, + if ( onError ) onError( e ); - copy: function ( source ) { + scope.manager.itemEnd( url ); + scope.manager.itemError( url ); - Path.prototype.copy.call( this, source ); + } ); - this.holes = []; + }, - for ( var i = 0, l = source.holes.length; i < l; i ++ ) { + setCrossOrigin: function ( /* value */ ) { - var hole = source.holes[ i ]; + return this; - this.holes.push( hole.clone() ); + }, - } + setPath: function ( value ) { + this.path = value; return this; } -} ); +}; /** * @author zz85 / http://www.lab4games.net/zz85/blog @@ -43016,375 +43896,6 @@ function AxesHelper( size ) { AxesHelper.prototype = Object.create( LineSegments.prototype ); AxesHelper.prototype.constructor = AxesHelper; -/** - * @author zz85 https://github.com/zz85 - * - * Centripetal CatmullRom Curve - which is useful for avoiding - * cusps and self-intersections in non-uniform catmull rom curves. - * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf - * - * curve.type accepts centripetal(default), chordal and catmullrom - * curve.tension is used for catmullrom which defaults to 0.5 - */ - - -/* -Based on an optimized c++ solution in - - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ - - http://ideone.com/NoEbVM - -This CubicPoly class could be used for reusing some variables and calculations, -but for three.js curve use, it could be possible inlined and flatten into a single function call -which can be placed in CurveUtils. -*/ - -function CubicPoly() { - - var c0 = 0, c1 = 0, c2 = 0, c3 = 0; - - /* - * Compute coefficients for a cubic polynomial - * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 - * such that - * p(0) = x0, p(1) = x1 - * and - * p'(0) = t0, p'(1) = t1. - */ - function init( x0, x1, t0, t1 ) { - - c0 = x0; - c1 = t0; - c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; - c3 = 2 * x0 - 2 * x1 + t0 + t1; - - } - - return { - - initCatmullRom: function ( x0, x1, x2, x3, tension ) { - - init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - - }, - - initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - - // compute tangents when parameterized in [t1,t2] - var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; - var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - - // rescale tangents for parametrization in [0,1] - t1 *= dt1; - t2 *= dt1; - - init( x1, x2, t1, t2 ); - - }, - - calc: function ( t ) { - - var t2 = t * t; - var t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; - - } - - }; - -} - -// - -var tmp = new Vector3(); -var px = new CubicPoly(); -var py = new CubicPoly(); -var pz = new CubicPoly(); - -function CatmullRomCurve3( points, closed, curveType, tension ) { - - Curve.call( this ); - - this.type = 'CatmullRomCurve3'; - - this.points = points || []; - this.closed = closed || false; - this.curveType = curveType || 'centripetal'; - this.tension = tension || 0.5; - -} - -CatmullRomCurve3.prototype = Object.create( Curve.prototype ); -CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; - -CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; - -CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) { - - var point = optionalTarget || new Vector3(); - - var points = this.points; - var l = points.length; - - var p = ( l - ( this.closed ? 0 : 1 ) ) * t; - var intPoint = Math.floor( p ); - var weight = p - intPoint; - - if ( this.closed ) { - - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; - - } else if ( weight === 0 && intPoint === l - 1 ) { - - intPoint = l - 2; - weight = 1; - - } - - var p0, p1, p2, p3; // 4 points - - if ( this.closed || intPoint > 0 ) { - - p0 = points[ ( intPoint - 1 ) % l ]; - - } else { - - // extrapolate first point - tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); - p0 = tmp; - - } - - p1 = points[ intPoint % l ]; - p2 = points[ ( intPoint + 1 ) % l ]; - - if ( this.closed || intPoint + 2 < l ) { - - p3 = points[ ( intPoint + 2 ) % l ]; - - } else { - - // extrapolate last point - tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); - p3 = tmp; - - } - - if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - - // init Centripetal / Chordal Catmull-Rom - var pow = this.curveType === 'chordal' ? 0.5 : 0.25; - var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); - var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); - var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - - // safety check for repeated points - if ( dt1 < 1e-4 ) dt1 = 1.0; - if ( dt0 < 1e-4 ) dt0 = dt1; - if ( dt2 < 1e-4 ) dt2 = dt1; - - px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); - py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); - pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - - } else if ( this.curveType === 'catmullrom' ) { - - px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); - py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); - pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); - - } - - point.set( - px.calc( weight ), - py.calc( weight ), - pz.calc( weight ) - ); - - return point; - -}; - -CatmullRomCurve3.prototype.copy = function ( source ) { - - Curve.prototype.copy.call( this, source ); - - this.points = []; - - for ( var i = 0, l = source.points.length; i < l; i ++ ) { - - var point = source.points[ i ]; - - this.points.push( point.clone() ); - - } - - this.closed = source.closed; - this.curveType = source.curveType; - this.tension = source.tension; - - return this; - -}; - -function CubicBezierCurve3( v0, v1, v2, v3 ) { - - Curve.call( this ); - - this.type = 'CubicBezierCurve3'; - - this.v0 = v0 || new Vector3(); - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); - this.v3 = v3 || new Vector3(); - -} - -CubicBezierCurve3.prototype = Object.create( Curve.prototype ); -CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; - -CubicBezierCurve3.prototype.isCubicBezierCurve3 = true; - -CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - - var point = optionalTarget || new Vector3(); - - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), - CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) - ); - - return point; - -}; - -CubicBezierCurve3.prototype.copy = function ( source ) { - - Curve.prototype.copy.call( this, source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); - - return this; - -}; - -function QuadraticBezierCurve3( v0, v1, v2 ) { - - Curve.call( this ); - - this.type = 'QuadraticBezierCurve3'; - - this.v0 = v0 || new Vector3(); - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); - -} - -QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); -QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; - -QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; - -QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - - var point = optionalTarget || new Vector3(); - - var v0 = this.v0, v1 = this.v1, v2 = this.v2; - - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ), - QuadraticBezier( t, v0.z, v1.z, v2.z ) - ); - - return point; - -}; - -QuadraticBezierCurve3.prototype.copy = function ( source ) { - - Curve.prototype.copy.call( this, source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - -}; - -function LineCurve3( v1, v2 ) { - - Curve.call( this ); - - this.type = 'LineCurve3'; - - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); - -} - -LineCurve3.prototype = Object.create( Curve.prototype ); -LineCurve3.prototype.constructor = LineCurve3; - -LineCurve3.prototype.isLineCurve3 = true; - -LineCurve3.prototype.getPoint = function ( t, optionalTarget ) { - - var point = optionalTarget || new Vector3(); - - if ( t === 1 ) { - - point.copy( this.v2 ); - - } else { - - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); - - } - - return point; - -}; - -// Line curve is linear, so we can overwrite default getPointAt - -LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) { - - return this.getPoint( u, optionalTarget ); - -}; - -LineCurve3.prototype.copy = function ( source ) { - - Curve.prototype.copy.call( this, source ); - - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - -}; - -function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - this.type = 'ArcCurve'; - -} - -ArcCurve.prototype = Object.create( EllipseCurve.prototype ); -ArcCurve.prototype.constructor = ArcCurve; - -ArcCurve.prototype.isArcCurve = true; - /** * @author alteredq / http://alteredqualia.com/ */ @@ -45075,4 +45586,4 @@ function CanvasRenderer() { } -export { WebGLRenderTargetCube, WebGLRenderTarget, WebGLRenderer, ShaderLib, UniformsLib, UniformsUtils, ShaderChunk, FogExp2, Fog, Scene, LensFlare, Sprite, LOD, SkinnedMesh, Skeleton, Bone, Mesh, LineSegments, LineLoop, Line, Points, Group, VideoTexture, DataTexture, CompressedTexture, CubeTexture, CanvasTexture, DepthTexture, Texture, CompressedTextureLoader, DataTextureLoader, CubeTextureLoader, TextureLoader, ObjectLoader, MaterialLoader, BufferGeometryLoader, DefaultLoadingManager, LoadingManager, JSONLoader, ImageLoader, ImageBitmapLoader, FontLoader, FileLoader, Loader, LoaderUtils, Cache, AudioLoader, SpotLightShadow, SpotLight, PointLight, RectAreaLight, HemisphereLight, DirectionalLightShadow, DirectionalLight, AmbientLight, LightShadow, Light, StereoCamera, PerspectiveCamera, OrthographicCamera, CubeCamera, ArrayCamera, Camera, AudioListener, PositionalAudio, AudioContext, AudioAnalyser, Audio, VectorKeyframeTrack, StringKeyframeTrack, QuaternionKeyframeTrack, NumberKeyframeTrack, ColorKeyframeTrack, BooleanKeyframeTrack, PropertyMixer, PropertyBinding, KeyframeTrack, AnimationUtils, AnimationObjectGroup, AnimationMixer, AnimationClip, Uniform, InstancedBufferGeometry, BufferGeometry, Geometry, InterleavedBufferAttribute, InstancedInterleavedBuffer, InterleavedBuffer, InstancedBufferAttribute, Face3, Object3D, Raycaster, Layers, EventDispatcher, Clock, QuaternionLinearInterpolant, LinearInterpolant, DiscreteInterpolant, CubicInterpolant, Interpolant, Triangle, _Math as Math, Spherical, Cylindrical, Plane, Frustum, Sphere, Ray, Matrix4, Matrix3, Box3, Box2, Line3, Euler, Vector4, Vector3, Vector2, Quaternion, Color, ImmediateRenderObject, VertexNormalsHelper, SpotLightHelper, SkeletonHelper, PointLightHelper, RectAreaLightHelper, HemisphereLightHelper, GridHelper, PolarGridHelper, FaceNormalsHelper, DirectionalLightHelper, CameraHelper, BoxHelper, Box3Helper, PlaneHelper, ArrowHelper, AxesHelper, CatmullRomCurve3, CubicBezierCurve3, QuadraticBezierCurve3, LineCurve3, ArcCurve, EllipseCurve, SplineCurve, CubicBezierCurve, QuadraticBezierCurve, LineCurve, Shape, Path, ShapePath, Font, CurvePath, Curve, ShapeUtils, SceneUtils, WebGLUtils, WireframeGeometry, ParametricGeometry, ParametricBufferGeometry, TetrahedronGeometry, TetrahedronBufferGeometry, OctahedronGeometry, OctahedronBufferGeometry, IcosahedronGeometry, IcosahedronBufferGeometry, DodecahedronGeometry, DodecahedronBufferGeometry, PolyhedronGeometry, PolyhedronBufferGeometry, TubeGeometry, TubeBufferGeometry, TorusKnotGeometry, TorusKnotBufferGeometry, TorusGeometry, TorusBufferGeometry, TextGeometry, TextBufferGeometry, SphereGeometry, SphereBufferGeometry, RingGeometry, RingBufferGeometry, PlaneGeometry, PlaneBufferGeometry, LatheGeometry, LatheBufferGeometry, ShapeGeometry, ShapeBufferGeometry, ExtrudeGeometry, ExtrudeBufferGeometry, EdgesGeometry, ConeGeometry, ConeBufferGeometry, CylinderGeometry, CylinderBufferGeometry, CircleGeometry, CircleBufferGeometry, BoxGeometry, BoxBufferGeometry, ShadowMaterial, SpriteMaterial, RawShaderMaterial, ShaderMaterial, PointsMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshPhongMaterial, MeshToonMaterial, MeshNormalMaterial, MeshLambertMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshBasicMaterial, LineDashedMaterial, LineBasicMaterial, Material, Float64BufferAttribute, Float32BufferAttribute, Uint32BufferAttribute, Int32BufferAttribute, Uint16BufferAttribute, Int16BufferAttribute, Uint8ClampedBufferAttribute, Uint8BufferAttribute, Int8BufferAttribute, BufferAttribute, REVISION, MOUSE, CullFaceNone, CullFaceBack, CullFaceFront, CullFaceFrontBack, FrontFaceDirectionCW, FrontFaceDirectionCCW, BasicShadowMap, PCFShadowMap, PCFSoftShadowMap, FrontSide, BackSide, DoubleSide, FlatShading, SmoothShading, NoColors, FaceColors, VertexColors, NoBlending, NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending, AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, MaxEquation, ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstAlphaFactor, OneMinusDstAlphaFactor, DstColorFactor, OneMinusDstColorFactor, SrcAlphaSaturateFactor, NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth, MultiplyOperation, MixOperation, AddOperation, NoToneMapping, LinearToneMapping, ReinhardToneMapping, Uncharted2ToneMapping, CineonToneMapping, UVMapping, CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping, SphericalReflectionMapping, CubeUVReflectionMapping, CubeUVRefractionMapping, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestFilter, NearestMipMapNearestFilter, NearestMipMapLinearFilter, LinearFilter, LinearMipMapNearestFilter, LinearMipMapLinearFilter, UnsignedByteType, ByteType, ShortType, UnsignedShortType, IntType, UnsignedIntType, FloatType, HalfFloatType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShort565Type, UnsignedInt248Type, AlphaFormat, RGBFormat, RGBAFormat, LuminanceFormat, LuminanceAlphaFormat, RGBEFormat, DepthFormat, DepthStencilFormat, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, LoopOnce, LoopRepeat, LoopPingPong, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, ZeroCurvatureEnding, ZeroSlopeEnding, WrapAroundEnding, TrianglesDrawMode, TriangleStripDrawMode, TriangleFanDrawMode, LinearEncoding, sRGBEncoding, GammaEncoding, RGBEEncoding, LogLuvEncoding, RGBM7Encoding, RGBM16Encoding, RGBDEncoding, BasicDepthPacking, RGBADepthPacking, BoxGeometry as CubeGeometry, Face4, LineStrip, LinePieces, MeshFaceMaterial, MultiMaterial, PointCloud, Particle, ParticleSystem, PointCloudMaterial, ParticleBasicMaterial, ParticleSystemMaterial, Vertex, DynamicBufferAttribute, Int8Attribute, Uint8Attribute, Uint8ClampedAttribute, Int16Attribute, Uint16Attribute, Int32Attribute, Uint32Attribute, Float32Attribute, Float64Attribute, ClosedSplineCurve3, SplineCurve3, Spline, AxisHelper, BoundingBoxHelper, EdgesHelper, WireframeHelper, XHRLoader, BinaryTextureLoader, GeometryUtils, ImageUtils, Projector, CanvasRenderer }; +export { WebGLRenderTargetCube, WebGLRenderTarget, WebGLRenderer, ShaderLib, UniformsLib, UniformsUtils, ShaderChunk, FogExp2, Fog, Scene, LensFlare, Sprite, LOD, SkinnedMesh, Skeleton, Bone, Mesh, LineSegments, LineLoop, Line, Points, Group, VideoTexture, DataTexture, CompressedTexture, CubeTexture, CanvasTexture, DepthTexture, Texture, CompressedTextureLoader, DataTextureLoader, CubeTextureLoader, TextureLoader, ObjectLoader, MaterialLoader, BufferGeometryLoader, DefaultLoadingManager, LoadingManager, JSONLoader, ImageLoader, ImageBitmapLoader, FontLoader, FileLoader, Loader, LoaderUtils, Cache, AudioLoader, SpotLightShadow, SpotLight, PointLight, RectAreaLight, HemisphereLight, DirectionalLightShadow, DirectionalLight, AmbientLight, LightShadow, Light, StereoCamera, PerspectiveCamera, OrthographicCamera, CubeCamera, ArrayCamera, Camera, AudioListener, PositionalAudio, AudioContext, AudioAnalyser, Audio, VectorKeyframeTrack, StringKeyframeTrack, QuaternionKeyframeTrack, NumberKeyframeTrack, ColorKeyframeTrack, BooleanKeyframeTrack, PropertyMixer, PropertyBinding, KeyframeTrack, AnimationUtils, AnimationObjectGroup, AnimationMixer, AnimationClip, Uniform, InstancedBufferGeometry, BufferGeometry, Geometry, InterleavedBufferAttribute, InstancedInterleavedBuffer, InterleavedBuffer, InstancedBufferAttribute, Face3, Object3D, Raycaster, Layers, EventDispatcher, Clock, QuaternionLinearInterpolant, LinearInterpolant, DiscreteInterpolant, CubicInterpolant, Interpolant, Triangle, _Math as Math, Spherical, Cylindrical, Plane, Frustum, Sphere, Ray, Matrix4, Matrix3, Box3, Box2, Line3, Euler, Vector4, Vector3, Vector2, Quaternion, Color, ImmediateRenderObject, VertexNormalsHelper, SpotLightHelper, SkeletonHelper, PointLightHelper, RectAreaLightHelper, HemisphereLightHelper, GridHelper, PolarGridHelper, FaceNormalsHelper, DirectionalLightHelper, CameraHelper, BoxHelper, Box3Helper, PlaneHelper, ArrowHelper, AxesHelper, Shape, Path, ShapePath, Font, CurvePath, Curve, ShapeUtils, SceneUtils, WebGLUtils, WireframeGeometry, ParametricGeometry, ParametricBufferGeometry, TetrahedronGeometry, TetrahedronBufferGeometry, OctahedronGeometry, OctahedronBufferGeometry, IcosahedronGeometry, IcosahedronBufferGeometry, DodecahedronGeometry, DodecahedronBufferGeometry, PolyhedronGeometry, PolyhedronBufferGeometry, TubeGeometry, TubeBufferGeometry, TorusKnotGeometry, TorusKnotBufferGeometry, TorusGeometry, TorusBufferGeometry, TextGeometry, TextBufferGeometry, SphereGeometry, SphereBufferGeometry, RingGeometry, RingBufferGeometry, PlaneGeometry, PlaneBufferGeometry, LatheGeometry, LatheBufferGeometry, ShapeGeometry, ShapeBufferGeometry, ExtrudeGeometry, ExtrudeBufferGeometry, EdgesGeometry, ConeGeometry, ConeBufferGeometry, CylinderGeometry, CylinderBufferGeometry, CircleGeometry, CircleBufferGeometry, BoxGeometry, BoxBufferGeometry, ShadowMaterial, SpriteMaterial, RawShaderMaterial, ShaderMaterial, PointsMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshPhongMaterial, MeshToonMaterial, MeshNormalMaterial, MeshLambertMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshBasicMaterial, LineDashedMaterial, LineBasicMaterial, Material, Float64BufferAttribute, Float32BufferAttribute, Uint32BufferAttribute, Int32BufferAttribute, Uint16BufferAttribute, Int16BufferAttribute, Uint8ClampedBufferAttribute, Uint8BufferAttribute, Int8BufferAttribute, BufferAttribute, ArcCurve, CatmullRomCurve3, CubicBezierCurve, CubicBezierCurve3, EllipseCurve, LineCurve, LineCurve3, QuadraticBezierCurve, QuadraticBezierCurve3, SplineCurve, REVISION, MOUSE, CullFaceNone, CullFaceBack, CullFaceFront, CullFaceFrontBack, FrontFaceDirectionCW, FrontFaceDirectionCCW, BasicShadowMap, PCFShadowMap, PCFSoftShadowMap, FrontSide, BackSide, DoubleSide, FlatShading, SmoothShading, NoColors, FaceColors, VertexColors, NoBlending, NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending, AddEquation, SubtractEquation, ReverseSubtractEquation, MinEquation, MaxEquation, ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstAlphaFactor, OneMinusDstAlphaFactor, DstColorFactor, OneMinusDstColorFactor, SrcAlphaSaturateFactor, NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth, MultiplyOperation, MixOperation, AddOperation, NoToneMapping, LinearToneMapping, ReinhardToneMapping, Uncharted2ToneMapping, CineonToneMapping, UVMapping, CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping, SphericalReflectionMapping, CubeUVReflectionMapping, CubeUVRefractionMapping, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestFilter, NearestMipMapNearestFilter, NearestMipMapLinearFilter, LinearFilter, LinearMipMapNearestFilter, LinearMipMapLinearFilter, UnsignedByteType, ByteType, ShortType, UnsignedShortType, IntType, UnsignedIntType, FloatType, HalfFloatType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShort565Type, UnsignedInt248Type, AlphaFormat, RGBFormat, RGBAFormat, LuminanceFormat, LuminanceAlphaFormat, RGBEFormat, DepthFormat, DepthStencilFormat, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, LoopOnce, LoopRepeat, LoopPingPong, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, ZeroCurvatureEnding, ZeroSlopeEnding, WrapAroundEnding, TrianglesDrawMode, TriangleStripDrawMode, TriangleFanDrawMode, LinearEncoding, sRGBEncoding, GammaEncoding, RGBEEncoding, LogLuvEncoding, RGBM7Encoding, RGBM16Encoding, RGBDEncoding, BasicDepthPacking, RGBADepthPacking, BoxGeometry as CubeGeometry, Face4, LineStrip, LinePieces, MeshFaceMaterial, MultiMaterial, PointCloud, Particle, ParticleSystem, PointCloudMaterial, ParticleBasicMaterial, ParticleSystemMaterial, Vertex, DynamicBufferAttribute, Int8Attribute, Uint8Attribute, Uint8ClampedAttribute, Int16Attribute, Uint16Attribute, Int32Attribute, Uint32Attribute, Float32Attribute, Float64Attribute, ClosedSplineCurve3, SplineCurve3, Spline, AxisHelper, BoundingBoxHelper, EdgesHelper, WireframeHelper, XHRLoader, BinaryTextureLoader, GeometryUtils, ImageUtils, Projector, CanvasRenderer }; diff --git a/package.json b/package.json index 34790245f2..6348a3e01a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "three", - "version": "0.88.0", + "version": "0.89.0", "description": "JavaScript 3D library", "main": "build/three.js", "repository": "mrdoob/three.js", diff --git a/src/constants.js b/src/constants.js index de79d888cd..38b6b95541 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,4 +1,4 @@ -export var REVISION = '89dev'; +export var REVISION = '89'; export var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; export var CullFaceNone = 0; export var CullFaceBack = 1; -- GitLab