From 3d04c0e8280d87cd9b7daf6c14c889aadc14d9f8 Mon Sep 17 00:00:00 2001 From: bbuchsbaum Date: Tue, 27 May 2025 20:49:32 -0400 Subject: [PATCH] validate data and color inputs --- .../lib/neurosurface/neurosurface.js | 68964 +--------------- inst/htmlwidgets/neurosurface/src/classes.js | 22 +- 2 files changed, 56 insertions(+), 68930 deletions(-) diff --git a/inst/htmlwidgets/lib/neurosurface/neurosurface.js b/inst/htmlwidgets/lib/neurosurface/neurosurface.js index 6001cdd..e19354a 100644 --- a/inst/htmlwidgets/lib/neurosurface/neurosurface.js +++ b/inst/htmlwidgets/lib/neurosurface/neurosurface.js @@ -1,68928 +1,36 @@ -var neurosurface = (function (exports) { - 'use strict'; - - /** - * @license - * Copyright 2010-2021 Three.js Authors - * SPDX-License-Identifier: MIT - */ - const REVISION = '132'; - const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; - const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; - const CullFaceNone = 0; - const CullFaceBack = 1; - const CullFaceFront = 2; - const CullFaceFrontBack = 3; - const BasicShadowMap = 0; - const PCFShadowMap = 1; - const PCFSoftShadowMap = 2; - const VSMShadowMap = 3; - const FrontSide = 0; - const BackSide = 1; - const DoubleSide = 2; - const FlatShading = 1; - const SmoothShading = 2; - const NoBlending = 0; - const NormalBlending = 1; - const AdditiveBlending = 2; - const SubtractiveBlending = 3; - const MultiplyBlending = 4; - const CustomBlending = 5; - const AddEquation = 100; - const SubtractEquation = 101; - const ReverseSubtractEquation = 102; - const MinEquation = 103; - const MaxEquation = 104; - const ZeroFactor = 200; - const OneFactor = 201; - const SrcColorFactor = 202; - const OneMinusSrcColorFactor = 203; - const SrcAlphaFactor = 204; - const OneMinusSrcAlphaFactor = 205; - const DstAlphaFactor = 206; - const OneMinusDstAlphaFactor = 207; - const DstColorFactor = 208; - const OneMinusDstColorFactor = 209; - const SrcAlphaSaturateFactor = 210; - const NeverDepth = 0; - const AlwaysDepth = 1; - const LessDepth = 2; - const LessEqualDepth = 3; - const EqualDepth = 4; - const GreaterEqualDepth = 5; - const GreaterDepth = 6; - const NotEqualDepth = 7; - const MultiplyOperation = 0; - const MixOperation = 1; - const AddOperation = 2; - const NoToneMapping = 0; - const LinearToneMapping = 1; - const ReinhardToneMapping = 2; - const CineonToneMapping = 3; - const ACESFilmicToneMapping = 4; - const CustomToneMapping = 5; - - const UVMapping = 300; - const CubeReflectionMapping = 301; - const CubeRefractionMapping = 302; - const EquirectangularReflectionMapping = 303; - const EquirectangularRefractionMapping = 304; - const CubeUVReflectionMapping = 306; - const CubeUVRefractionMapping = 307; - const RepeatWrapping = 1000; - const ClampToEdgeWrapping = 1001; - const MirroredRepeatWrapping = 1002; - const NearestFilter = 1003; - const NearestMipmapNearestFilter = 1004; - const NearestMipMapNearestFilter = 1004; - const NearestMipmapLinearFilter = 1005; - const NearestMipMapLinearFilter = 1005; - const LinearFilter = 1006; - const LinearMipmapNearestFilter = 1007; - const LinearMipMapNearestFilter = 1007; - const LinearMipmapLinearFilter = 1008; - const LinearMipMapLinearFilter = 1008; - const UnsignedByteType = 1009; - const ByteType = 1010; - const ShortType = 1011; - const UnsignedShortType = 1012; - const IntType = 1013; - const UnsignedIntType = 1014; - const FloatType = 1015; - const HalfFloatType = 1016; - const UnsignedShort4444Type = 1017; - const UnsignedShort5551Type = 1018; - const UnsignedShort565Type = 1019; - const UnsignedInt248Type = 1020; - const AlphaFormat = 1021; - const RGBFormat = 1022; - const RGBAFormat = 1023; - const LuminanceFormat = 1024; - const LuminanceAlphaFormat = 1025; - const RGBEFormat = RGBAFormat; - const DepthFormat = 1026; - const DepthStencilFormat = 1027; - const RedFormat = 1028; - const RedIntegerFormat = 1029; - const RGFormat = 1030; - const RGIntegerFormat = 1031; - const RGBIntegerFormat = 1032; - const RGBAIntegerFormat = 1033; - - const RGB_S3TC_DXT1_Format = 33776; - const RGBA_S3TC_DXT1_Format = 33777; - const RGBA_S3TC_DXT3_Format = 33778; - const RGBA_S3TC_DXT5_Format = 33779; - const RGB_PVRTC_4BPPV1_Format = 35840; - const RGB_PVRTC_2BPPV1_Format = 35841; - const RGBA_PVRTC_4BPPV1_Format = 35842; - const RGBA_PVRTC_2BPPV1_Format = 35843; - const RGB_ETC1_Format = 36196; - const RGB_ETC2_Format = 37492; - const RGBA_ETC2_EAC_Format = 37496; - const RGBA_ASTC_4x4_Format = 37808; - const RGBA_ASTC_5x4_Format = 37809; - const RGBA_ASTC_5x5_Format = 37810; - const RGBA_ASTC_6x5_Format = 37811; - const RGBA_ASTC_6x6_Format = 37812; - const RGBA_ASTC_8x5_Format = 37813; - const RGBA_ASTC_8x6_Format = 37814; - const RGBA_ASTC_8x8_Format = 37815; - const RGBA_ASTC_10x5_Format = 37816; - const RGBA_ASTC_10x6_Format = 37817; - const RGBA_ASTC_10x8_Format = 37818; - const RGBA_ASTC_10x10_Format = 37819; - const RGBA_ASTC_12x10_Format = 37820; - const RGBA_ASTC_12x12_Format = 37821; - const RGBA_BPTC_Format = 36492; - const SRGB8_ALPHA8_ASTC_4x4_Format = 37840; - const SRGB8_ALPHA8_ASTC_5x4_Format = 37841; - const SRGB8_ALPHA8_ASTC_5x5_Format = 37842; - const SRGB8_ALPHA8_ASTC_6x5_Format = 37843; - const SRGB8_ALPHA8_ASTC_6x6_Format = 37844; - const SRGB8_ALPHA8_ASTC_8x5_Format = 37845; - const SRGB8_ALPHA8_ASTC_8x6_Format = 37846; - const SRGB8_ALPHA8_ASTC_8x8_Format = 37847; - const SRGB8_ALPHA8_ASTC_10x5_Format = 37848; - const SRGB8_ALPHA8_ASTC_10x6_Format = 37849; - const SRGB8_ALPHA8_ASTC_10x8_Format = 37850; - const SRGB8_ALPHA8_ASTC_10x10_Format = 37851; - const SRGB8_ALPHA8_ASTC_12x10_Format = 37852; - const SRGB8_ALPHA8_ASTC_12x12_Format = 37853; - const LoopOnce = 2200; - const LoopRepeat = 2201; - const LoopPingPong = 2202; - const InterpolateDiscrete = 2300; - const InterpolateLinear = 2301; - const InterpolateSmooth = 2302; - const ZeroCurvatureEnding = 2400; - const ZeroSlopeEnding = 2401; - const WrapAroundEnding = 2402; - const NormalAnimationBlendMode = 2500; - const AdditiveAnimationBlendMode = 2501; - const TrianglesDrawMode = 0; - const TriangleStripDrawMode = 1; - const TriangleFanDrawMode = 2; - const LinearEncoding = 3000; - const sRGBEncoding = 3001; - const GammaEncoding = 3007; - const RGBEEncoding = 3002; - const LogLuvEncoding = 3003; - const RGBM7Encoding = 3004; - const RGBM16Encoding = 3005; - const RGBDEncoding = 3006; - const BasicDepthPacking = 3200; - const RGBADepthPacking = 3201; - const TangentSpaceNormalMap = 0; - const ObjectSpaceNormalMap = 1; - - const ZeroStencilOp = 0; - const KeepStencilOp = 7680; - const ReplaceStencilOp = 7681; - const IncrementStencilOp = 7682; - const DecrementStencilOp = 7683; - const IncrementWrapStencilOp = 34055; - const DecrementWrapStencilOp = 34056; - const InvertStencilOp = 5386; - - const NeverStencilFunc = 512; - const LessStencilFunc = 513; - const EqualStencilFunc = 514; - const LessEqualStencilFunc = 515; - const GreaterStencilFunc = 516; - const NotEqualStencilFunc = 517; - const GreaterEqualStencilFunc = 518; - const AlwaysStencilFunc = 519; - - const StaticDrawUsage = 35044; - const DynamicDrawUsage = 35048; - const StreamDrawUsage = 35040; - const StaticReadUsage = 35045; - const DynamicReadUsage = 35049; - const StreamReadUsage = 35041; - const StaticCopyUsage = 35046; - const DynamicCopyUsage = 35050; - const StreamCopyUsage = 35042; - - const GLSL1 = '100'; - const GLSL3 = '300 es'; - - /** - * https://github.com/mrdoob/eventdispatcher.js/ - */ - - class EventDispatcher { - - addEventListener( type, listener ) { - - if ( this._listeners === undefined ) this._listeners = {}; - - const listeners = this._listeners; - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - - } - - } - - hasEventListener( type, listener ) { - - if ( this._listeners === undefined ) return false; - - const listeners = this._listeners; - - return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; - - } - - removeEventListener( type, listener ) { - - if ( this._listeners === undefined ) return; - - const listeners = this._listeners; - const listenerArray = listeners[ type ]; - - if ( listenerArray !== undefined ) { - - const index = listenerArray.indexOf( listener ); - - if ( index !== - 1 ) { - - listenerArray.splice( index, 1 ); - - } - - } - - } - - dispatchEvent( event ) { - - if ( this._listeners === undefined ) return; - - const listeners = this._listeners; - const listenerArray = listeners[ event.type ]; - - if ( listenerArray !== undefined ) { - - event.target = this; - - // Make a copy, in case listeners are removed while iterating. - const array = listenerArray.slice( 0 ); - - for ( let i = 0, l = array.length; i < l; i ++ ) { - - array[ i ].call( this, event ); - - } - - event.target = null; - - } - - } - - } - - const _lut = []; - - for ( let i = 0; i < 256; i ++ ) { - - _lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 ); - - } - - let _seed = 1234567; - - - const DEG2RAD = Math.PI / 180; - const RAD2DEG = 180 / Math.PI; - - // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 - function generateUUID() { - - const d0 = Math.random() * 0xffffffff | 0; - const d1 = Math.random() * 0xffffffff | 0; - const d2 = Math.random() * 0xffffffff | 0; - const d3 = Math.random() * 0xffffffff | 0; - const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + - _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + - _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + - _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; - - // .toUpperCase() here flattens concatenated strings to save heap memory space. - return uuid.toUpperCase(); - - } - - function clamp( value, min, max ) { - - return Math.max( min, Math.min( max, value ) ); - - } - - // compute euclidian modulo of m % n - // https://en.wikipedia.org/wiki/Modulo_operation - function euclideanModulo( n, m ) { - - return ( ( n % m ) + m ) % m; - - } - - // Linear mapping from range to range - function mapLinear( x, a1, a2, b1, b2 ) { - - return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); - - } - - // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ - function inverseLerp( x, y, value ) { - - if ( x !== y ) { - - return ( value - x ) / ( y - x ); - - } else { - - return 0; - - } - - } - - // https://en.wikipedia.org/wiki/Linear_interpolation - function lerp$2( x, y, t ) { - - return ( 1 - t ) * x + t * y; - - } - - // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ - function damp( x, y, lambda, dt ) { - - return lerp$2( x, y, 1 - Math.exp( - lambda * dt ) ); - - } - - // https://www.desmos.com/calculator/vcsjnyz7x4 - function pingpong( x, length = 1 ) { - - return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); - - } - - // http://en.wikipedia.org/wiki/Smoothstep - function smoothstep( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * ( 3 - 2 * x ); - - } - - function smootherstep( x, min, max ) { - - if ( x <= min ) return 0; - if ( x >= max ) return 1; - - x = ( x - min ) / ( max - min ); - - return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); - - } - - // Random integer from interval - function randInt( low, high ) { - - return low + Math.floor( Math.random() * ( high - low + 1 ) ); - - } - - // Random float from interval - function randFloat( low, high ) { - - return low + Math.random() * ( high - low ); - - } - - // Random float from <-range/2, range/2> interval - function randFloatSpread( range ) { - - return range * ( 0.5 - Math.random() ); - - } - - // Deterministic pseudo-random float in the interval [ 0, 1 ] - function seededRandom( s ) { - - if ( s !== undefined ) _seed = s % 2147483647; - - // Park-Miller algorithm - - _seed = _seed * 16807 % 2147483647; - - return ( _seed - 1 ) / 2147483646; - - } - - function degToRad( degrees ) { - - return degrees * DEG2RAD; - - } - - function radToDeg( radians ) { - - return radians * RAD2DEG; - - } - - function isPowerOfTwo( value ) { - - return ( value & ( value - 1 ) ) === 0 && value !== 0; - - } - - function ceilPowerOfTwo( value ) { - - return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); - - } - - function floorPowerOfTwo( value ) { - - return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); - - } - - function setQuaternionFromProperEuler( q, a, b, c, order ) { - - // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles - - // rotations are applied to the axes in the order specified by 'order' - // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' - // angles are in radians - - const cos = Math.cos; - const sin = Math.sin; - - const c2 = cos( b / 2 ); - const s2 = sin( b / 2 ); - - const c13 = cos( ( a + c ) / 2 ); - const s13 = sin( ( a + c ) / 2 ); - - const c1_3 = cos( ( a - c ) / 2 ); - const s1_3 = sin( ( a - c ) / 2 ); - - const c3_1 = cos( ( c - a ) / 2 ); - const s3_1 = sin( ( c - a ) / 2 ); - - switch ( order ) { - - case 'XYX': - q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); - break; - - case 'YZY': - q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); - break; - - case 'ZXZ': - q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); - break; - - case 'XZX': - q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); - break; - - case 'YXY': - q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); - break; - - case 'ZYZ': - q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); - break; - - default: - console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); - - } - - } - - var MathUtils = /*#__PURE__*/Object.freeze({ - __proto__: null, - DEG2RAD: DEG2RAD, - RAD2DEG: RAD2DEG, - generateUUID: generateUUID, - clamp: clamp, - euclideanModulo: euclideanModulo, - mapLinear: mapLinear, - inverseLerp: inverseLerp, - lerp: lerp$2, - damp: damp, - pingpong: pingpong, - smoothstep: smoothstep, - smootherstep: smootherstep, - randInt: randInt, - randFloat: randFloat, - randFloatSpread: randFloatSpread, - seededRandom: seededRandom, - degToRad: degToRad, - radToDeg: radToDeg, - isPowerOfTwo: isPowerOfTwo, - ceilPowerOfTwo: ceilPowerOfTwo, - floorPowerOfTwo: floorPowerOfTwo, - setQuaternionFromProperEuler: setQuaternionFromProperEuler - }); - - class Vector2 { - - constructor( x = 0, y = 0 ) { - - this.x = x; - this.y = y; - - } - - get width() { - - return this.x; - - } - - set width( value ) { - - this.x = value; - - } - - get height() { - - return this.y; - - } - - set height( value ) { - - this.y = value; - - } - - set( x, y ) { - - this.x = x; - this.y = y; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - - return this; - - } - - add( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - - return this; - - } - - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - - return this; - - } - - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - - return this; - - } - - sub( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - - return this; - - } - - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - - return this; - - } - - multiply( v ) { - - this.x *= v.x; - this.y *= v.y; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - - return this; - - } - - divide( v ) { - - this.x /= v.x; - this.y /= v.y; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - applyMatrix3( m ) { - - const x = this.x, y = this.y; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; - - return this; - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - - return this; - - } - - ceil() { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - - return this; - - } - - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - - return this; - - } - - roundToZero() { - - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y; - - } - - cross( v ) { - - return this.x * v.y - this.y * v.x; - - } - - lengthSq() { - - return this.x * this.x + this.y * this.y; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - angle() { - - // computes the angle in radians with respect to the positive x-axis - - const angle = Math.atan2( - this.y, - this.x ) + Math.PI; - - return angle; - - } - - distanceTo( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - } - - distanceToSquared( v ) { - - const dx = this.x - v.x, dy = this.y - v.y; - return dx * dx + dy * dy; - - } - - manhattanDistanceTo( v ) { - - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - - return this; - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - - return array; - - } - - fromBufferAttribute( attribute, index, offset ) { - - if ( offset !== undefined ) { - - console.warn( 'THREE.Vector2: offset has been removed from .fromBufferAttribute().' ); - - } - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - - return this; - - } - - rotateAround( center, angle ) { - - const c = Math.cos( angle ), s = Math.sin( angle ); - - const x = this.x - center.x; - const y = this.y - center.y; - - this.x = x * c - y * s + center.x; - this.y = x * s + y * c + center.y; - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - - return this; - - } - - } - - Vector2.prototype.isVector2 = true; - - class Matrix3 { - - constructor() { - - this.elements = [ - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ]; - - if ( arguments.length > 0 ) { - - console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); - - } - - } - - set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { - - const te = this.elements; - - te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; - te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; - te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; - - return this; - - } - - identity() { - - this.set( - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 - - ); - - return this; - - } - - copy( m ) { - - const te = this.elements; - const me = m.elements; - - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; - te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; - te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; - - return this; - - } - - extractBasis( xAxis, yAxis, zAxis ) { - - xAxis.setFromMatrix3Column( this, 0 ); - yAxis.setFromMatrix3Column( this, 1 ); - zAxis.setFromMatrix3Column( this, 2 ); - - return this; - - } - - setFromMatrix4( m ) { - - const me = m.elements; - - this.set( - - me[ 0 ], me[ 4 ], me[ 8 ], - me[ 1 ], me[ 5 ], me[ 9 ], - me[ 2 ], me[ 6 ], me[ 10 ] - - ); - - return this; - - } - - multiply( m ) { - - return this.multiplyMatrices( this, m ); - - } - - premultiply( m ) { - - return this.multiplyMatrices( m, this ); - - } - - multiplyMatrices( a, b ) { - - const ae = a.elements; - const be = b.elements; - const te = this.elements; - - const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; - const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; - const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; - - const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; - const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; - const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; - te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; - te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; - te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; - te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; - - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; - te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; - te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; - - return this; - - } - - multiplyScalar( s ) { - - const te = this.elements; - - te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; - te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; - te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; - - return this; - - } - - determinant() { - - const te = this.elements; - - const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], - d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], - g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; - - return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; - - } - - invert() { - - const te = this.elements, - - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], - n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], - n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], - - t11 = n33 * n22 - n32 * n23, - t12 = n32 * n13 - n33 * n12, - t13 = n23 * n12 - n22 * n13, - - det = n11 * t11 + n21 * t12 + n31 * t13; - - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - - const detInv = 1 / det; - - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; - te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; - - te[ 3 ] = t12 * detInv; - te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; - te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; - - te[ 6 ] = t13 * detInv; - te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; - te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; - - return this; - - } - - transpose() { - - let tmp; - const m = this.elements; - - tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; - tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; - tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; - - return this; - - } - - getNormalMatrix( matrix4 ) { - - return this.setFromMatrix4( matrix4 ).invert().transpose(); - - } - - transposeIntoArray( r ) { - - const m = this.elements; - - r[ 0 ] = m[ 0 ]; - r[ 1 ] = m[ 3 ]; - r[ 2 ] = m[ 6 ]; - r[ 3 ] = m[ 1 ]; - r[ 4 ] = m[ 4 ]; - r[ 5 ] = m[ 7 ]; - r[ 6 ] = m[ 2 ]; - r[ 7 ] = m[ 5 ]; - r[ 8 ] = m[ 8 ]; - - return this; - - } - - setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { - - const c = Math.cos( rotation ); - const s = Math.sin( rotation ); - - this.set( - sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, - - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, - 0, 0, 1 - ); - - return this; - - } - - scale( sx, sy ) { - - const te = this.elements; - - te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx; - te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy; - - return this; - - } - - rotate( theta ) { - - const c = Math.cos( theta ); - const s = Math.sin( theta ); - - const te = this.elements; - - const a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ]; - const a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ]; - - te[ 0 ] = c * a11 + s * a21; - te[ 3 ] = c * a12 + s * a22; - te[ 6 ] = c * a13 + s * a23; - - te[ 1 ] = - s * a11 + c * a21; - te[ 4 ] = - s * a12 + c * a22; - te[ 7 ] = - s * a13 + c * a23; - - return this; - - } - - translate( tx, ty ) { - - const te = this.elements; - - te[ 0 ] += tx * te[ 2 ]; te[ 3 ] += tx * te[ 5 ]; te[ 6 ] += tx * te[ 8 ]; - te[ 1 ] += ty * te[ 2 ]; te[ 4 ] += ty * te[ 5 ]; te[ 7 ] += ty * te[ 8 ]; - - return this; - - } - - equals( matrix ) { - - const te = this.elements; - const me = matrix.elements; - - for ( let i = 0; i < 9; i ++ ) { - - if ( te[ i ] !== me[ i ] ) return false; - - } - - return true; - - } - - fromArray( array, offset = 0 ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.elements[ i ] = array[ i + offset ]; - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const te = this.elements; - - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - - array[ offset + 3 ] = te[ 3 ]; - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - array[ offset + 8 ] = te[ 8 ]; - - return array; - - } - - clone() { - - return new this.constructor().fromArray( this.elements ); - - } - - } - - Matrix3.prototype.isMatrix3 = true; - - let _canvas; - - class ImageUtils { - - static getDataURL( image ) { - - if ( /^data:/i.test( image.src ) ) { - - return image.src; - - } - - if ( typeof HTMLCanvasElement == 'undefined' ) { - - return image.src; - - } - - let canvas; - - if ( image instanceof HTMLCanvasElement ) { - - canvas = image; - - } else { - - if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - - _canvas.width = image.width; - _canvas.height = image.height; - - const context = _canvas.getContext( '2d' ); - - if ( image instanceof ImageData ) { - - context.putImageData( image, 0, 0 ); - - } else { - - context.drawImage( image, 0, 0, image.width, image.height ); - - } - - canvas = _canvas; - - } - - if ( canvas.width > 2048 || canvas.height > 2048 ) { - - console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); - - return canvas.toDataURL( 'image/jpeg', 0.6 ); - - } else { - - return canvas.toDataURL( 'image/png' ); - - } - - } - - } - - let textureId = 0; - - class Texture extends EventDispatcher { - - constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = 1, encoding = LinearEncoding ) { - - super(); - - Object.defineProperty( this, 'id', { value: textureId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - - this.image = image; - this.mipmaps = []; - - this.mapping = mapping; - - this.wrapS = wrapS; - this.wrapT = wrapT; - - this.magFilter = magFilter; - this.minFilter = minFilter; - - this.anisotropy = anisotropy; - - this.format = format; - this.internalFormat = null; - this.type = type; - - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - this.center = new Vector2( 0, 0 ); - this.rotation = 0; - - this.matrixAutoUpdate = true; - this.matrix = new Matrix3(); - - this.generateMipmaps = true; - this.premultiplyAlpha = false; - this.flipY = true; - this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) - - // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. - // - // Also changing the encoding after already used by a Material will not automatically make the Material - // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. - this.encoding = encoding; - - this.version = 0; - this.onUpdate = null; - - this.isRenderTargetTexture = false; - - } - - updateMatrix() { - - this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.name = source.name; - - this.image = source.image; - this.mipmaps = source.mipmaps.slice( 0 ); - - this.mapping = source.mapping; - - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; - - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; - - this.anisotropy = source.anisotropy; - - this.format = source.format; - this.internalFormat = source.internalFormat; - this.type = source.type; - - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - this.center.copy( source.center ); - this.rotation = source.rotation; - - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrix.copy( source.matrix ); - - this.generateMipmaps = source.generateMipmaps; - this.premultiplyAlpha = source.premultiplyAlpha; - this.flipY = source.flipY; - this.unpackAlignment = source.unpackAlignment; - this.encoding = source.encoding; - - return this; - - } - - toJSON( meta ) { - - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { - - return meta.textures[ this.uuid ]; - - } - - const output = { - - 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 ], - - format: this.format, - type: this.type, - encoding: this.encoding, - - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, - - flipY: this.flipY, - - premultiplyAlpha: this.premultiplyAlpha, - unpackAlignment: this.unpackAlignment - - }; - - if ( this.image !== undefined ) { - - // TODO: Move to THREE.Image - - const image = this.image; - - if ( image.uuid === undefined ) { - - image.uuid = generateUUID(); // UGH - - } - - if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) { - - let url; - - if ( Array.isArray( image ) ) { - - // process array of images e.g. CubeTexture - - url = []; - - for ( let i = 0, l = image.length; i < l; i ++ ) { - - // check cube texture with data textures - - if ( image[ i ].isDataTexture ) { - - url.push( serializeImage( image[ i ].image ) ); - - } else { - - url.push( serializeImage( image[ i ] ) ); - - } - - } - - } else { - - // process single image - - url = serializeImage( image ); - - } - - meta.images[ image.uuid ] = { - uuid: image.uuid, - url: url - }; - - } - - output.image = image.uuid; - - } - - if ( ! isRootObject ) { - - meta.textures[ this.uuid ] = output; - - } - - return output; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - transformUv( uv ) { - - if ( this.mapping !== UVMapping ) return uv; - - uv.applyMatrix3( this.matrix ); - - if ( uv.x < 0 || uv.x > 1 ) { - - switch ( this.wrapS ) { - - case RepeatWrapping: - - uv.x = uv.x - Math.floor( uv.x ); - break; - - case ClampToEdgeWrapping: - - uv.x = uv.x < 0 ? 0 : 1; - break; - - case MirroredRepeatWrapping: - - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - - uv.x = Math.ceil( uv.x ) - uv.x; - - } else { - - uv.x = uv.x - Math.floor( uv.x ); - - } - - break; - - } - - } - - if ( uv.y < 0 || uv.y > 1 ) { - - switch ( this.wrapT ) { - - case RepeatWrapping: - - uv.y = uv.y - Math.floor( uv.y ); - break; - - case ClampToEdgeWrapping: - - uv.y = uv.y < 0 ? 0 : 1; - break; - - case MirroredRepeatWrapping: - - if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - - uv.y = Math.ceil( uv.y ) - uv.y; - - } else { - - uv.y = uv.y - Math.floor( uv.y ); - - } - - break; - - } - - } - - if ( this.flipY ) { - - uv.y = 1 - uv.y; - - } - - return uv; - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - } - - Texture.DEFAULT_IMAGE = undefined; - Texture.DEFAULT_MAPPING = UVMapping; - - Texture.prototype.isTexture = true; - - function serializeImage( image ) { - - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - - // default images - - return ImageUtils.getDataURL( image ); - - } else { - - if ( image.data ) { - - // images of DataTexture - - return { - data: Array.prototype.slice.call( image.data ), - width: image.width, - height: image.height, - type: image.data.constructor.name - }; - - } else { - - console.warn( 'THREE.Texture: Unable to serialize Texture.' ); - return {}; - - } - - } - - } - - class Vector4 { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - } - - get width() { - - return this.z; - - } - - set width( value ) { - - this.z = value; - - } - - get height() { - - return this.w; - - } - - set height( value ) { - - this.w = value; - - } - - set( x, y, z, w ) { - - this.x = x; - this.y = y; - this.z = z; - this.w = w; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setZ( z ) { - - this.z = z; - - return this; - - } - - setW( w ) { - - this.w = w; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y, this.z, this.w ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; - - return this; - - } - - add( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; - this.w += s; - - return this; - - } - - addVectors( 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( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - this.w += v.w * s; - - return this; - - } - - sub( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; - - return this; - - } - - subVectors( 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; - - } - - multiply( v ) { - - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - this.w *= v.w; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; - - return this; - - } - - applyMatrix4( m ) { - - const x = this.x, y = this.y, z = this.z, w = this.w; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; - this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - setAxisAngleFromQuaternion( q ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - - // q is assumed to be normalized - - this.w = 2 * Math.acos( q.w ); - - const s = Math.sqrt( 1 - q.w * q.w ); - - if ( s < 0.0001 ) { - - this.x = 1; - this.y = 0; - this.z = 0; - - } else { - - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; - - } - - return this; - - } - - setAxisAngleFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - let angle, x, y, z; // variables for result - const epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - - te = m.elements, - - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { - - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms - - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - - // this singularity is identity matrix so angle = 0 - - this.set( 1, 0, 0, 0 ); - - return this; // zero angle, arbitrary axis - - } - - // otherwise this singularity is angle = 180 - - angle = Math.PI; - - const xx = ( m11 + 1 ) / 2; - const yy = ( m22 + 1 ) / 2; - const zz = ( m33 + 1 ) / 2; - const xy = ( m12 + m21 ) / 4; - const xz = ( m13 + m31 ) / 4; - const yz = ( m23 + m32 ) / 4; - - if ( ( xx > yy ) && ( xx > zz ) ) { - - // m11 is the largest diagonal term - - if ( xx < epsilon ) { - - x = 0; - y = 0.707106781; - z = 0.707106781; - - } else { - - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; - - } - - } else if ( yy > zz ) { - - // m22 is the largest diagonal term - - if ( yy < epsilon ) { - - x = 0.707106781; - y = 0; - z = 0.707106781; - - } else { - - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; - - } - - } else { - - // m33 is the largest diagonal term so base result on this - - if ( zz < epsilon ) { - - x = 0.707106781; - y = 0.707106781; - z = 0; - - } else { - - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; - - } - - } - - this.set( x, y, z, angle ); - - return this; // return 180 deg rotation - - } - - // as we have reached here there are no singularities so we can handle normally - - let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - - if ( Math.abs( s ) < 0.001 ) s = 1; - - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case - - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - - return this; - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - this.w = Math.min( this.w, v.w ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - this.w = Math.max( this.w, v.w ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - this.w = Math.max( min.w, Math.min( max.w, this.w ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - 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() { - - 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() { - - 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() { - - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - this.w = - this.w; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - - } - - lengthSq() { - - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - this.w = v1.w + ( v2.w - v1.w ) * alpha; - - return this; - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; - - return array; - - } - - fromBufferAttribute( attribute, index, offset ) { - - if ( offset !== undefined ) { - - console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' ); - - } - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - this.w = Math.random(); - - return this; - - } - - } - - Vector4.prototype.isVector4 = true; - - /* - In options, we can specify: - * Texture parameters for an auto-generated target texture - * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers - */ - class WebGLRenderTarget extends EventDispatcher { - - constructor( width, height, options = {} ) { - - super(); - - this.width = width; - this.height = height; - this.depth = 1; - - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; - - this.viewport = new Vector4( 0, 0, width, height ); - - this.texture = new Texture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - this.texture.isRenderTargetTexture = true; - - this.texture.image = { width: width, height: height, depth: 1 }; - - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.internalFormat = options.internalFormat !== undefined ? options.internalFormat : null; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; - - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false; - this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; - - } - - setTexture( texture ) { - - texture.image = { - width: this.width, - height: this.height, - depth: this.depth - }; - - this.texture = texture; - - } - - setSize( width, height, depth = 1 ) { - - if ( this.width !== width || this.height !== height || this.depth !== depth ) { - - this.width = width; - this.height = height; - this.depth = depth; - - this.texture.image.width = width; - this.texture.image.height = height; - this.texture.image.depth = depth; - - this.dispose(); - - } - - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.width = source.width; - this.height = source.height; - this.depth = source.depth; - - this.viewport.copy( source.viewport ); - - this.texture = source.texture.clone(); - this.texture.image = { ...this.texture.image }; // See #20328. - - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; - this.depthTexture = source.depthTexture; - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - } - - WebGLRenderTarget.prototype.isWebGLRenderTarget = true; - - class WebGLMultipleRenderTargets extends WebGLRenderTarget { - - constructor( width, height, count ) { - - super( width, height ); - - const texture = this.texture; - - this.texture = []; - - for ( let i = 0; i < count; i ++ ) { - - this.texture[ i ] = texture.clone(); - - } - - } - - setSize( width, height, depth = 1 ) { - - if ( this.width !== width || this.height !== height || this.depth !== depth ) { - - this.width = width; - this.height = height; - this.depth = depth; - - for ( let i = 0, il = this.texture.length; i < il; i ++ ) { - - this.texture[ i ].image.width = width; - this.texture[ i ].image.height = height; - this.texture[ i ].image.depth = depth; - - } - - this.dispose(); - - } - - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); - - return this; - - } - - copy( source ) { - - this.dispose(); - - this.width = source.width; - this.height = source.height; - this.depth = source.depth; - - this.viewport.set( 0, 0, this.width, this.height ); - this.scissor.set( 0, 0, this.width, this.height ); - - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; - this.depthTexture = source.depthTexture; - - this.texture.length = 0; - - for ( let i = 0, il = source.texture.length; i < il; i ++ ) { - - this.texture[ i ] = source.texture[ i ].clone(); - - } - - return this; - - } - - } - - WebGLMultipleRenderTargets.prototype.isWebGLMultipleRenderTargets = true; - - class WebGLMultisampleRenderTarget extends WebGLRenderTarget { - - constructor( width, height, options ) { - - super( width, height, options ); - - this.samples = 4; - - } - - copy( source ) { - - super.copy.call( this, source ); - - this.samples = source.samples; - - return this; - - } - - } - - WebGLMultisampleRenderTarget.prototype.isWebGLMultisampleRenderTarget = true; - - class Quaternion { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - } - - static slerp( qa, qb, qm, t ) { - - console.warn( 'THREE.Quaternion: Static .slerp() has been deprecated. Use qm.slerpQuaternions( qa, qb, t ) instead.' ); - return qm.slerpQuaternions( qa, qb, t ); - - } - - static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - - // fuzz-free, array-based Quaternion SLERP operation - - let x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; - - if ( t === 0 ) { - - dst[ dstOffset + 0 ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - return; - - } - - if ( t === 1 ) { - - dst[ dstOffset + 0 ] = x1; - dst[ dstOffset + 1 ] = y1; - dst[ dstOffset + 2 ] = z1; - dst[ dstOffset + 3 ] = w1; - return; - - } - - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - - let s = 1 - t; - const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; - - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { - - const sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); - - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; - - } - - const tDir = t * dir; - - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; - - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { - - const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; - - } - - } - - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - - } - - static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - - const x0 = src0[ srcOffset0 ]; - const y0 = src0[ srcOffset0 + 1 ]; - const z0 = src0[ srcOffset0 + 2 ]; - const w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 ]; - const y1 = src1[ srcOffset1 + 1 ]; - const z1 = src1[ srcOffset1 + 2 ]; - const w1 = src1[ srcOffset1 + 3 ]; - - dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; - dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; - dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; - dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; - - return dst; - - } - - get x() { - - return this._x; - - } - - set x( value ) { - - this._x = value; - this._onChangeCallback(); - - } - - get y() { - - return this._y; - - } - - set y( value ) { - - this._y = value; - this._onChangeCallback(); - - } - - get z() { - - return this._z; - - } - - set z( value ) { - - this._z = value; - this._onChangeCallback(); - - } - - get w() { - - return this._w; - - } - - set w( value ) { - - this._w = value; - this._onChangeCallback(); - - } - - set( x, y, z, w ) { - - this._x = x; - this._y = y; - this._z = z; - this._w = w; - - this._onChangeCallback(); - - return this; - - } - - clone() { - - return new this.constructor( this._x, this._y, this._z, this._w ); - - } - - copy( quaternion ) { - - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; - - this._onChangeCallback(); - - return this; - - } - - setFromEuler( euler, update ) { - - if ( ! ( euler && euler.isEuler ) ) { - - throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' ); - - } - - const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - const cos = Math.cos; - const sin = Math.sin; - - const c1 = cos( x / 2 ); - const c2 = cos( y / 2 ); - const c3 = cos( z / 2 ); - - const s1 = sin( x / 2 ); - const s2 = sin( y / 2 ); - const s3 = sin( z / 2 ); - - switch ( order ) { - - case 'XYZ': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'YXZ': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - case 'ZXY': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'ZYX': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - case 'YZX': - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; - break; - - case 'XZY': - this._x = s1 * c2 * c3 - c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 + s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; - break; - - default: - console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); - - } - - if ( update !== false ) this._onChangeCallback(); - - return this; - - } - - setFromAxisAngle( axis, angle ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - - // assumes axis is normalized - - const halfAngle = angle / 2, s = Math.sin( halfAngle ); - - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); - - this._onChangeCallback(); - - return this; - - } - - setFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - const te = m.elements, - - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], - - trace = m11 + m22 + m33; - - if ( trace > 0 ) { - - const s = 0.5 / Math.sqrt( trace + 1.0 ); - - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; - - } else if ( m11 > m22 && m11 > m33 ) { - - const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; - - } else if ( m22 > m33 ) { - - const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; - - } else { - - const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; - - } - - this._onChangeCallback(); - - return this; - - } - - setFromUnitVectors( vFrom, vTo ) { - - // assumes direction vectors vFrom and vTo are normalized - - let r = vFrom.dot( vTo ) + 1; - - if ( r < Number.EPSILON ) { - - // vFrom and vTo point in opposite directions - - r = 0; - - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - - this._x = - vFrom.y; - this._y = vFrom.x; - this._z = 0; - this._w = r; - - } else { - - this._x = 0; - this._y = - vFrom.z; - this._z = vFrom.y; - this._w = r; - - } - - } else { - - // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 - - this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; - this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; - this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; - this._w = r; - - } - - return this.normalize(); - - } - - angleTo( q ) { - - return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); - - } - - rotateTowards( q, step ) { - - const angle = this.angleTo( q ); - - if ( angle === 0 ) return this; - - const t = Math.min( 1, step / angle ); - - this.slerp( q, t ); - - return this; - - } - - identity() { - - return this.set( 0, 0, 0, 1 ); - - } - - invert() { - - // quaternion is assumed to have unit length - - return this.conjugate(); - - } - - conjugate() { - - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; - - this._onChangeCallback(); - - return this; - - } - - dot( v ) { - - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - - } - - lengthSq() { - - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; - - } - - length() { - - return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); - - } - - normalize() { - - let l = this.length(); - - if ( l === 0 ) { - - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; - - } else { - - l = 1 / l; - - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; - - } - - this._onChangeCallback(); - - return this; - - } - - multiply( q, p ) { - - if ( p !== undefined ) { - - console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); - return this.multiplyQuaternions( q, p ); - - } - - return this.multiplyQuaternions( this, q ); - - } - - premultiply( q ) { - - return this.multiplyQuaternions( q, this ); - - } - - multiplyQuaternions( a, b ) { - - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - - const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - - this._onChangeCallback(); - - return this; - - } - - slerp( qb, t ) { - - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); - - const x = this._x, y = this._y, z = this._z, w = this._w; - - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - - let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - - if ( cosHalfTheta < 0 ) { - - this._w = - qb._w; - this._x = - qb._x; - this._y = - qb._y; - this._z = - qb._z; - - cosHalfTheta = - cosHalfTheta; - - } else { - - this.copy( qb ); - - } - - if ( cosHalfTheta >= 1.0 ) { - - this._w = w; - this._x = x; - this._y = y; - this._z = z; - - return this; - - } - - const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - - if ( sqrSinHalfTheta <= Number.EPSILON ) { - - const s = 1 - t; - this._w = s * w + t * this._w; - this._x = s * x + t * this._x; - this._y = s * y + t * this._y; - this._z = s * z + t * this._z; - - this.normalize(); - this._onChangeCallback(); - - return this; - - } - - const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); - const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); - - this._onChangeCallback(); - - return this; - - } - - slerpQuaternions( qa, qb, t ) { - - this.copy( qa ).slerp( qb, t ); - - } - - equals( quaternion ) { - - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); - - } - - fromArray( array, offset = 0 ) { - - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; - - this._onChangeCallback(); - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this._x = attribute.getX( index ); - this._y = attribute.getY( index ); - this._z = attribute.getZ( index ); - this._w = attribute.getW( index ); - - return this; - - } - - _onChange( callback ) { - - this._onChangeCallback = callback; - - return this; - - } - - _onChangeCallback() {} - - } - - Quaternion.prototype.isQuaternion = true; - - class Vector3 { - - constructor( x = 0, y = 0, z = 0 ) { - - this.x = x; - this.y = y; - this.z = z; - - } - - set( x, y, z ) { - - if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) - - this.x = x; - this.y = y; - this.z = z; - - return this; - - } - - setScalar( scalar ) { - - this.x = scalar; - this.y = scalar; - this.z = scalar; - - return this; - - } - - setX( x ) { - - this.x = x; - - return this; - - } - - setY( y ) { - - this.y = y; - - return this; - - } - - setZ( z ) { - - this.z = z; - - return this; - - } - - setComponent( index, value ) { - - switch ( index ) { - - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - default: throw new Error( 'index is out of range: ' + index ); - - } - - return this; - - } - - getComponent( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - default: throw new Error( 'index is out of range: ' + index ); - - } - - } - - clone() { - - return new this.constructor( this.x, this.y, this.z ); - - } - - copy( v ) { - - this.x = v.x; - this.y = v.y; - this.z = v.z; - - return this; - - } - - add( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); - - } - - this.x += v.x; - this.y += v.y; - this.z += v.z; - - return this; - - } - - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; - - return this; - - } - - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - - return this; - - } - - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - - return this; - - } - - sub( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); - - } - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - - return this; - - } - - subScalar( s ) { - - this.x -= s; - this.y -= s; - this.z -= s; - - return this; - - } - - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - - return this; - - } - - multiply( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); - return this.multiplyVectors( v, w ); - - } - - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - - return this; - - } - - multiplyScalar( scalar ) { - - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - - return this; - - } - - multiplyVectors( a, b ) { - - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; - - return this; - - } - - applyEuler( euler ) { - - if ( ! ( euler && euler.isEuler ) ) { - - console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' ); - - } - - return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); - - } - - applyAxisAngle( axis, angle ) { - - return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); - - } - - applyMatrix3( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; - this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; - - return this; - - } - - applyNormalMatrix( m ) { - - return this.applyMatrix3( m ).normalize(); - - } - - applyMatrix4( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - - this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; - this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; - this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; - - return this; - - } - - applyQuaternion( q ) { - - const x = this.x, y = this.y, z = this.z; - const qx = q.x, qy = q.y, qz = q.z, qw = q.w; - - // calculate quat * vector - - const ix = qw * x + qy * z - qz * y; - const iy = qw * y + qz * x - qx * z; - const iz = qw * z + qx * y - qy * x; - const iw = - qx * x - qy * y - qz * z; - - // calculate result * inverse quat - - this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; - this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; - this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; - - return this; - - } - - project( camera ) { - - return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); - - } - - unproject( camera ) { - - return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); - - } - - transformDirection( m ) { - - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; - - this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; - this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; - this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; - - return this.normalize(); - - } - - divide( v ) { - - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; - - return this; - - } - - divideScalar( scalar ) { - - return this.multiplyScalar( 1 / scalar ); - - } - - min( v ) { - - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); - - return this; - - } - - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - - return this; - - } - - clamp( min, max ) { - - // assumes min < max, componentwise - - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - - return this; - - } - - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - - return this; - - } - - clampLength( min, max ) { - - const length = this.length(); - - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - - } - - floor() { - - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - - return this; - - } - - ceil() { - - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - - return this; - - } - - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - - return this; - - } - - roundToZero() { - - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - - return this; - - } - - negate() { - - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - - return this; - - } - - dot( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z; - - } - - // TODO lengthSquared? - - lengthSq() { - - return this.x * this.x + this.y * this.y + this.z * this.z; - - } - - length() { - - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - - } - - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - - } - - normalize() { - - return this.divideScalar( this.length() || 1 ); - - } - - setLength( length ) { - - return this.normalize().multiplyScalar( length ); - - } - - lerp( v, alpha ) { - - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - - return this; - - } - - lerpVectors( v1, v2, alpha ) { - - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - - return this; - - } - - cross( v, w ) { - - if ( w !== undefined ) { - - console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); - return this.crossVectors( v, w ); - - } - - return this.crossVectors( this, v ); - - } - - crossVectors( a, b ) { - - const ax = a.x, ay = a.y, az = a.z; - const bx = b.x, by = b.y, bz = b.z; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; - - return this; - - } - - projectOnVector( v ) { - - const denominator = v.lengthSq(); - - if ( denominator === 0 ) return this.set( 0, 0, 0 ); - - const scalar = v.dot( this ) / denominator; - - return this.copy( v ).multiplyScalar( scalar ); - - } - - projectOnPlane( planeNormal ) { - - _vector$c.copy( this ).projectOnVector( planeNormal ); - - return this.sub( _vector$c ); - - } - - reflect( normal ) { - - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length - - return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - - } - - angleTo( v ) { - - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - - if ( denominator === 0 ) return Math.PI / 2; - - const theta = this.dot( v ) / denominator; - - // clamp, to handle numerical problems - - return Math.acos( clamp( theta, - 1, 1 ) ); - - } - - distanceTo( v ) { - - return Math.sqrt( this.distanceToSquared( v ) ); - - } - - distanceToSquared( v ) { - - const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - - return dx * dx + dy * dy + dz * dz; - - } - - manhattanDistanceTo( v ) { - - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); - - } - - setFromSpherical( s ) { - - return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); - - } - - setFromSphericalCoords( radius, phi, theta ) { - - const sinPhiRadius = Math.sin( phi ) * radius; - - this.x = sinPhiRadius * Math.sin( theta ); - this.y = Math.cos( phi ) * radius; - this.z = sinPhiRadius * Math.cos( theta ); - - return this; - - } - - setFromCylindrical( c ) { - - return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); - - } - - setFromCylindricalCoords( radius, theta, y ) { - - this.x = radius * Math.sin( theta ); - this.y = y; - this.z = radius * Math.cos( theta ); - - return this; - - } - - setFromMatrixPosition( m ) { - - const e = m.elements; - - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; - - return this; - - } - - setFromMatrixScale( m ) { - - const sx = this.setFromMatrixColumn( m, 0 ).length(); - const sy = this.setFromMatrixColumn( m, 1 ).length(); - const sz = this.setFromMatrixColumn( m, 2 ).length(); - - this.x = sx; - this.y = sy; - this.z = sz; - - return this; - - } - - setFromMatrixColumn( m, index ) { - - return this.fromArray( m.elements, index * 4 ); - - } - - setFromMatrix3Column( m, index ) { - - return this.fromArray( m.elements, index * 3 ); - - } - - equals( v ) { - - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - - } - - fromArray( array, offset = 0 ) { - - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - - return array; - - } - - fromBufferAttribute( attribute, index, offset ) { - - if ( offset !== undefined ) { - - console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' ); - - } - - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - - return this; - - } - - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - - return this; - - } - - } - - Vector3.prototype.isVector3 = true; - - const _vector$c = /*@__PURE__*/ new Vector3(); - const _quaternion$4 = /*@__PURE__*/ new Quaternion(); - - class Box3 { - - constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { - - this.min = min; - this.max = max; - - } - - set( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - } - - setFromArray( array ) { - - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; - - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; - - for ( let i = 0, l = array.length; i < l; i += 3 ) { - - const x = array[ i ]; - const y = array[ i + 1 ]; - const z = array[ i + 2 ]; - - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; - - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; - - } - - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); - - return this; - - } - - setFromBufferAttribute( attribute ) { - - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; - - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; - - for ( let i = 0, l = attribute.count; i < l; i ++ ) { - - const x = attribute.getX( i ); - const y = attribute.getY( i ); - const z = attribute.getZ( i ); - - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; - - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; - - } - - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); - - return this; - - } - - setFromPoints( points ) { - - this.makeEmpty(); - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - this.expandByPoint( points[ i ] ); - - } - - return this; - - } - - setFromCenterAndSize( center, size ) { - - const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); - - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - } - - setFromObject( object ) { - - this.makeEmpty(); - - return this.expandByObject( object ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - } - - makeEmpty() { - - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; - - return this; - - } - - isEmpty() { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - - } - - getCenter( target ) { - - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - } - - getSize( target ) { - - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); - - } - - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - } - - expandByVector( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - } - - expandByScalar( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - } - - expandByObject( object ) { - - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms - - object.updateWorldMatrix( false, false ); - - const geometry = object.geometry; - - if ( geometry !== undefined ) { - - if ( geometry.boundingBox === null ) { - - geometry.computeBoundingBox(); - - } - - _box$3.copy( geometry.boundingBox ); - _box$3.applyMatrix4( object.matrixWorld ); - - this.union( _box$3 ); - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - this.expandByObject( children[ i ] ); - - } - - return this; - - } - - containsPoint( point ) { - - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ? false : true; - - } - - containsBox( box ) { - - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y && - this.min.z <= box.min.z && box.max.z <= this.max.z; - - } - - getParameter( point, target ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ), - ( point.z - this.min.z ) / ( this.max.z - this.min.z ) - ); - - } - - intersectsBox( box ) { - - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; - - } - - intersectsSphere( sphere ) { - - // Find the point on the AABB closest to the sphere center. - this.clampPoint( sphere.center, _vector$b ); - - // If that point is inside the sphere, the AABB and sphere intersect. - return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); - - } - - intersectsPlane( plane ) { - - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. - - let min, max; - - if ( plane.normal.x > 0 ) { - - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; - - } else { - - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; - - } - - if ( plane.normal.y > 0 ) { - - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; - - } else { - - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; - - } - - if ( plane.normal.z > 0 ) { - - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; - - } else { - - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; - - } - - return ( min <= - plane.constant && max >= - plane.constant ); - - } - - intersectsTriangle( triangle ) { - - if ( this.isEmpty() ) { - - return false; - - } - - // compute box center and extents - this.getCenter( _center ); - _extents.subVectors( this.max, _center ); - - // translate triangle to aabb origin - _v0$2.subVectors( triangle.a, _center ); - _v1$7.subVectors( triangle.b, _center ); - _v2$3.subVectors( triangle.c, _center ); - - // compute edge vectors for triangle - _f0.subVectors( _v1$7, _v0$2 ); - _f1.subVectors( _v2$3, _v1$7 ); - _f2.subVectors( _v0$2, _v2$3 ); - - // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb - // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation - // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) - let axes = [ - 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, - _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, - - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 - ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ) ) { - - return false; - - } - - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ) ) { - - return false; - - } - - // finally testing the face normal of the triangle - // use already existing triangle edge vectors here - _triangleNormal.crossVectors( _f0, _f1 ); - axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; - - return satForAxes( axes, _v0$2, _v1$7, _v2$3, _extents ); - - } - - clampPoint( point, target ) { - - return target.copy( point ).clamp( this.min, this.max ); - - } - - distanceToPoint( point ) { - - const clampedPoint = _vector$b.copy( point ).clamp( this.min, this.max ); - - return clampedPoint.sub( point ).length(); - - } - - getBoundingSphere( target ) { - - this.getCenter( target.center ); - - target.radius = this.getSize( _vector$b ).length() * 0.5; - - return target; - - } - - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. - if ( this.isEmpty() ) this.makeEmpty(); - - return this; - - } - - union( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - } - - applyMatrix4( matrix ) { - - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; - - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 - - this.setFromPoints( _points ); - - return this; - - } - - translate( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - } - - equals( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - - } - - Box3.prototype.isBox3 = true; - - const _points = [ - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3(), - /*@__PURE__*/ new Vector3() - ]; - - const _vector$b = /*@__PURE__*/ new Vector3(); - - const _box$3 = /*@__PURE__*/ new Box3(); - - // triangle centered vertices - - const _v0$2 = /*@__PURE__*/ new Vector3(); - const _v1$7 = /*@__PURE__*/ new Vector3(); - const _v2$3 = /*@__PURE__*/ new Vector3(); - - // triangle edge vectors - - const _f0 = /*@__PURE__*/ new Vector3(); - const _f1 = /*@__PURE__*/ new Vector3(); - const _f2 = /*@__PURE__*/ new Vector3(); - - const _center = /*@__PURE__*/ new Vector3(); - const _extents = /*@__PURE__*/ new Vector3(); - const _triangleNormal = /*@__PURE__*/ new Vector3(); - const _testAxis = /*@__PURE__*/ new Vector3(); - - function satForAxes( axes, v0, v1, v2, extents ) { - - for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { - - _testAxis.fromArray( axes, i ); - // project the aabb onto the seperating axis - const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); - // project all 3 vertices of the triangle onto the seperating axis - const p0 = v0.dot( _testAxis ); - const p1 = v1.dot( _testAxis ); - const p2 = v2.dot( _testAxis ); - // actual test, basically see if either of the most extreme of the triangle points intersects r - if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { - - // points of the projected triangle are outside the projected half-length of the aabb - // the axis is seperating and we can exit - return false; - - } - - } - - return true; - - } - - const _box$2 = /*@__PURE__*/ new Box3(); - const _v1$6 = /*@__PURE__*/ new Vector3(); - const _toFarthestPoint = /*@__PURE__*/ new Vector3(); - const _toPoint = /*@__PURE__*/ new Vector3(); - - class Sphere { - - constructor( center = new Vector3(), radius = - 1 ) { - - this.center = center; - this.radius = radius; - - } - - set( center, radius ) { - - this.center.copy( center ); - this.radius = radius; - - return this; - - } - - setFromPoints( points, optionalCenter ) { - - const center = this.center; - - if ( optionalCenter !== undefined ) { - - center.copy( optionalCenter ); - - } else { - - _box$2.setFromPoints( points ).getCenter( center ); - - } - - let maxRadiusSq = 0; - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); - - } - - this.radius = Math.sqrt( maxRadiusSq ); - - return this; - - } - - copy( sphere ) { - - this.center.copy( sphere.center ); - this.radius = sphere.radius; - - return this; - - } - - isEmpty() { - - return ( this.radius < 0 ); - - } - - makeEmpty() { - - this.center.set( 0, 0, 0 ); - this.radius = - 1; - - return this; - - } - - containsPoint( point ) { - - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); - - } - - distanceToPoint( point ) { - - return ( point.distanceTo( this.center ) - this.radius ); - - } - - intersectsSphere( sphere ) { - - const radiusSum = this.radius + sphere.radius; - - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - - } - - intersectsBox( box ) { - - return box.intersectsSphere( this ); - - } - - intersectsPlane( plane ) { - - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; - - } - - clampPoint( point, target ) { - - const deltaLengthSq = this.center.distanceToSquared( point ); - - target.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { - - target.sub( this.center ).normalize(); - target.multiplyScalar( this.radius ).add( this.center ); - - } - - return target; - - } - - getBoundingBox( target ) { - - if ( this.isEmpty() ) { - - // Empty sphere produces empty bounding box - target.makeEmpty(); - return target; - - } - - target.set( this.center, this.center ); - target.expandByScalar( this.radius ); - - return target; - - } - - applyMatrix4( matrix ) { - - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); - - return this; - - } - - translate( offset ) { - - this.center.add( offset ); - - return this; - - } - - expandByPoint( point ) { - - // from https://github.com/juj/MathGeoLib/blob/2940b99b99cfe575dd45103ef20f4019dee15b54/src/Geometry/Sphere.cpp#L649-L671 - - _toPoint.subVectors( point, this.center ); - - const lengthSq = _toPoint.lengthSq(); - - if ( lengthSq > ( this.radius * this.radius ) ) { - - const length = Math.sqrt( lengthSq ); - const missingRadiusHalf = ( length - this.radius ) * 0.5; - - // Nudge this sphere towards the target point. Add half the missing distance to radius, - // and the other half to position. This gives a tighter enclosure, instead of if - // the whole missing distance were just added to radius. - - this.center.add( _toPoint.multiplyScalar( missingRadiusHalf / length ) ); - this.radius += missingRadiusHalf; - - } - - return this; - - } - - union( sphere ) { - - // from https://github.com/juj/MathGeoLib/blob/2940b99b99cfe575dd45103ef20f4019dee15b54/src/Geometry/Sphere.cpp#L759-L769 - - // To enclose another sphere into this sphere, we only need to enclose two points: - // 1) Enclose the farthest point on the other sphere into this sphere. - // 2) Enclose the opposite point of the farthest point into this sphere. - - _toFarthestPoint.subVectors( sphere.center, this.center ).normalize().multiplyScalar( sphere.radius ); - - this.expandByPoint( _v1$6.copy( sphere.center ).add( _toFarthestPoint ) ); - this.expandByPoint( _v1$6.copy( sphere.center ).sub( _toFarthestPoint ) ); - - return this; - - } - - equals( sphere ) { - - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - } - - const _vector$a = /*@__PURE__*/ new Vector3(); - const _segCenter = /*@__PURE__*/ new Vector3(); - const _segDir = /*@__PURE__*/ new Vector3(); - const _diff = /*@__PURE__*/ new Vector3(); - - const _edge1 = /*@__PURE__*/ new Vector3(); - const _edge2 = /*@__PURE__*/ new Vector3(); - const _normal$1 = /*@__PURE__*/ new Vector3(); - - class Ray { - - constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { - - this.origin = origin; - this.direction = direction; - - } - - set( origin, direction ) { - - this.origin.copy( origin ); - this.direction.copy( direction ); - - return this; - - } - - copy( ray ) { - - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); - - return this; - - } - - at( t, target ) { - - return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); - - } - - lookAt( v ) { - - this.direction.copy( v ).sub( this.origin ).normalize(); - - return this; - - } - - recast( t ) { - - this.origin.copy( this.at( t, _vector$a ) ); - - return this; - - } - - closestPointToPoint( point, target ) { - - target.subVectors( point, this.origin ); - - const directionDistance = target.dot( this.direction ); - - if ( directionDistance < 0 ) { - - return target.copy( this.origin ); - - } - - return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - - } - - distanceToPoint( point ) { - - return Math.sqrt( this.distanceSqToPoint( point ) ); - - } - - distanceSqToPoint( point ) { - - const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); - - // point behind the ray - - if ( directionDistance < 0 ) { - - return this.origin.distanceToSquared( point ); - - } - - _vector$a.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - - return _vector$a.distanceToSquared( point ); - - } - - distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h - // It returns the min distance between the ray and the segment - // defined by v0 and v1 - // It can also set two optional targets : - // - The closest point on the ray - // - The closest point on the segment - - _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - _segDir.copy( v1 ).sub( v0 ).normalize(); - _diff.copy( this.origin ).sub( _segCenter ); - - const segExtent = v0.distanceTo( v1 ) * 0.5; - const a01 = - this.direction.dot( _segDir ); - const b0 = _diff.dot( this.direction ); - const b1 = - _diff.dot( _segDir ); - const c = _diff.lengthSq(); - const det = Math.abs( 1 - a01 * a01 ); - let s0, s1, sqrDist, extDet; - - if ( det > 0 ) { - - // The ray and segment are not parallel. - - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; - - if ( s0 >= 0 ) { - - if ( s1 >= - extDet ) { - - if ( s1 <= extDet ) { - - // region 0 - // Minimum at interior points of ray and segment. - - const invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - - } else { - - // region 1 - - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - // region 5 - - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } else { - - if ( s1 <= - extDet ) { - - // region 4 - - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } else if ( s1 <= extDet ) { - - // region 3 - - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; - - } else { - - // region 2 - - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - } - - } else { - - // Ray and segment are parallel. - - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - - } - - if ( optionalPointOnRay ) { - - optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); - - } - - if ( optionalPointOnSegment ) { - - optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter ); - - } - - return sqrDist; - - } - - intersectSphere( sphere, target ) { - - _vector$a.subVectors( sphere.center, this.origin ); - const tca = _vector$a.dot( this.direction ); - const d2 = _vector$a.dot( _vector$a ) - tca * tca; - const radius2 = sphere.radius * sphere.radius; - - if ( d2 > radius2 ) return null; - - const thc = Math.sqrt( radius2 - d2 ); - - // t0 = first intersect point - entrance on front of sphere - const t0 = tca - thc; - - // t1 = second intersect point - exit point on back of sphere - const t1 = tca + thc; - - // test to see if both t0 and t1 are behind the ray - if so, return null - if ( t0 < 0 && t1 < 0 ) return null; - - // test to see if t0 is behind the ray: - // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, - // in order to always return an intersect point that is in front of the ray. - if ( t0 < 0 ) return this.at( t1, target ); - - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, target ); - - } - - intersectsSphere( sphere ) { - - return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); - - } - - distanceToPlane( plane ) { - - const denominator = plane.normal.dot( this.direction ); - - if ( denominator === 0 ) { - - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { - - return 0; - - } - - // Null is preferable to undefined since undefined means.... it is undefined - - return null; - - } - - const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - - // Return if the ray never intersects the plane - - return t >= 0 ? t : null; - - } - - intersectPlane( plane, target ) { - - const t = this.distanceToPlane( plane ); - - if ( t === null ) { - - return null; - - } - - return this.at( t, target ); - - } - - intersectsPlane( plane ) { - - // check if the ray lies on the plane first - - const distToPoint = plane.distanceToPoint( this.origin ); - - if ( distToPoint === 0 ) { - - return true; - - } - - const denominator = plane.normal.dot( this.direction ); - - if ( denominator * distToPoint < 0 ) { - - return true; - - } - - // ray origin is behind the plane (and is pointing behind it) - - return false; - - } - - intersectBox( box, target ) { - - let tmin, tmax, tymin, tymax, tzmin, tzmax; - - const invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; - - const origin = this.origin; - - if ( invdirx >= 0 ) { - - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; - - } else { - - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; - - } - - if ( invdiry >= 0 ) { - - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; - - } else { - - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; - - } - - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - - // These lines also handle the case where tmin or tmax is NaN - // (result of 0 * Infinity). x !== x returns true if x is NaN - - if ( tymin > tmin || tmin !== tmin ) tmin = tymin; - - if ( tymax < tmax || tmax !== tmax ) tmax = tymax; - - if ( invdirz >= 0 ) { - - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; - - } else { - - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; - - } - - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - - //return point closest to the ray (positive side) - - if ( tmax < 0 ) return null; - - return this.at( tmin >= 0 ? tmin : tmax, target ); - - } - - intersectsBox( box ) { - - return this.intersectBox( box, _vector$a ) !== null; - - } - - intersectTriangle( a, b, c, backfaceCulling, target ) { - - // Compute the offset origin, edges, and normal. - - // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - - _edge1.subVectors( b, a ); - _edge2.subVectors( c, a ); - _normal$1.crossVectors( _edge1, _edge2 ); - - // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, - // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by - // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) - // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) - // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) - let DdN = this.direction.dot( _normal$1 ); - let sign; - - if ( DdN > 0 ) { - - if ( backfaceCulling ) return null; - sign = 1; - - } else if ( DdN < 0 ) { - - sign = - 1; - DdN = - DdN; - - } else { - - return null; - - } - - _diff.subVectors( this.origin, a ); - const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); - - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { - - return null; - - } - - const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); - - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { - - return null; - - } - - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { - - return null; - - } - - // Line intersects triangle, check if ray does. - const QdN = - sign * _diff.dot( _normal$1 ); - - // t < 0, no intersection - if ( QdN < 0 ) { - - return null; - - } - - // Ray intersects triangle. - return this.at( QdN / DdN, target ); - - } - - applyMatrix4( matrix4 ) { - - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); - - return this; - - } - - equals( ray ) { - - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - } - - class Matrix4 { - - constructor() { - - this.elements = [ - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ]; - - if ( arguments.length > 0 ) { - - console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); - - } - - } - - set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - - const te = this.elements; - - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; - - return this; - - } - - identity() { - - this.set( - - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - clone() { - - return new Matrix4().fromArray( this.elements ); - - } - - copy( m ) { - - const te = this.elements; - const me = m.elements; - - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; - te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; - te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; - te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; - - return this; - - } - - copyPosition( m ) { - - const te = this.elements, me = m.elements; - - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; - - return this; - - } - - setFromMatrix3( m ) { - - const me = m.elements; - - this.set( - - me[ 0 ], me[ 3 ], me[ 6 ], 0, - me[ 1 ], me[ 4 ], me[ 7 ], 0, - me[ 2 ], me[ 5 ], me[ 8 ], 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - extractBasis( xAxis, yAxis, zAxis ) { - - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); - - return this; - - } - - makeBasis( xAxis, yAxis, zAxis ) { - - this.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, - 0, 0, 0, 1 - ); - - return this; - - } - - extractRotation( m ) { - - // this method does not support reflection matrices - - const te = this.elements; - const me = m.elements; - - const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); - const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); - const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); - - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; - - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; - - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; - - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; - - return this; - - } - - makeRotationFromEuler( euler ) { - - if ( ! ( euler && euler.isEuler ) ) { - - console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); - - } - - const te = this.elements; - - const x = euler.x, y = euler.y, z = euler.z; - const a = Math.cos( x ), b = Math.sin( x ); - const c = Math.cos( y ), d = Math.sin( y ); - const e = Math.cos( z ), f = Math.sin( z ); - - if ( euler.order === 'XYZ' ) { - - const ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[ 0 ] = c * e; - te[ 4 ] = - c * f; - te[ 8 ] = d; - - te[ 1 ] = af + be * d; - te[ 5 ] = ae - bf * d; - te[ 9 ] = - b * c; - - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; - - } else if ( euler.order === 'YXZ' ) { - - const ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; - - te[ 1 ] = a * f; - te[ 5 ] = a * e; - te[ 9 ] = - b; - - te[ 2 ] = cf * b - de; - te[ 6 ] = df + ce * b; - te[ 10 ] = a * c; - - } else if ( euler.order === 'ZXY' ) { - - const ce = c * e, cf = c * f, de = d * e, df = d * f; - - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; - - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; - - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; - - } else if ( euler.order === 'ZYX' ) { - - const ae = a * e, af = a * f, be = b * e, bf = b * f; - - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; - - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; - - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; - - } else if ( euler.order === 'YZX' ) { - - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; - - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; - - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; - - } else if ( euler.order === 'XZY' ) { - - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; - - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; - - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; - - } - - // bottom row - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; - - // last column - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; - - return this; - - } - - makeRotationFromQuaternion( q ) { - - return this.compose( _zero, q, _one ); - - } - - lookAt( eye, target, up ) { - - const te = this.elements; - - _z.subVectors( eye, target ); - - if ( _z.lengthSq() === 0 ) { - - // eye and target are in the same position - - _z.z = 1; - - } - - _z.normalize(); - _x.crossVectors( up, _z ); - - if ( _x.lengthSq() === 0 ) { - - // up and z are parallel - - if ( Math.abs( up.z ) === 1 ) { - - _z.x += 0.0001; - - } else { - - _z.z += 0.0001; - - } - - _z.normalize(); - _x.crossVectors( up, _z ); - - } - - _x.normalize(); - _y.crossVectors( _z, _x ); - - te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; - te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; - te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; - - return this; - - } - - multiply( m, n ) { - - if ( n !== undefined ) { - - console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); - return this.multiplyMatrices( m, n ); - - } - - return this.multiplyMatrices( this, m ); - - } - - premultiply( m ) { - - return this.multiplyMatrices( m, this ); - - } - - multiplyMatrices( a, b ) { - - const ae = a.elements; - const be = b.elements; - const te = this.elements; - - const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - - const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - - te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - - return this; - - } - - multiplyScalar( s ) { - - const te = this.elements; - - te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; - te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; - te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; - te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; - - return this; - - } - - determinant() { - - const te = this.elements; - - const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - - return ( - n41 * ( - + n14 * n23 * n32 - - n13 * n24 * n32 - - n14 * n22 * n33 - + n12 * n24 * n33 - + n13 * n22 * n34 - - n12 * n23 * n34 - ) + - n42 * ( - + n11 * n23 * n34 - - n11 * n24 * n33 - + n14 * n21 * n33 - - n13 * n21 * n34 - + n13 * n24 * n31 - - n14 * n23 * n31 - ) + - n43 * ( - + n11 * n24 * n32 - - n11 * n22 * n34 - - n14 * n21 * n32 - + n12 * n21 * n34 - + n14 * n22 * n31 - - n12 * n24 * n31 - ) + - n44 * ( - - n13 * n22 * n31 - - n11 * n23 * n32 - + n11 * n22 * n33 - + n13 * n21 * n32 - - n12 * n21 * n33 - + n12 * n23 * n31 - ) - - ); - - } - - transpose() { - - const te = this.elements; - let tmp; - - tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; - tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; - tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - - tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; - tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; - tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; - - return this; - - } - - setPosition( x, y, z ) { - - const te = this.elements; - - if ( x.isVector3 ) { - - te[ 12 ] = x.x; - te[ 13 ] = x.y; - te[ 14 ] = x.z; - - } else { - - te[ 12 ] = x; - te[ 13 ] = y; - te[ 14 ] = z; - - } - - return this; - - } - - invert() { - - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - const te = this.elements, - - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], - n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], - n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], - n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], - - t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, - t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, - t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, - t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; - - const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - - const detInv = 1 / det; - - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; - te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; - te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; - - te[ 4 ] = t12 * detInv; - te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; - te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; - te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; - - te[ 8 ] = t13 * detInv; - te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; - te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; - te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; - - te[ 12 ] = t14 * detInv; - te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; - te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; - te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; - - return this; - - } - - scale( v ) { - - const te = this.elements; - const x = v.x, y = v.y, z = v.z; - - te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; - te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; - te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; - te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; - - return this; - - } - - getMaxScaleOnAxis() { - - const te = this.elements; - - const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; - - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); - - } - - makeTranslation( x, y, z ) { - - this.set( - - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationX( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationY( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationZ( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); - - this.set( - - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeRotationAxis( axis, angle ) { - - // Based on http://www.gamedev.net/reference/articles/article1199.asp - - const c = Math.cos( angle ); - const s = Math.sin( angle ); - const t = 1 - c; - const x = axis.x, y = axis.y, z = axis.z; - const tx = t * x, ty = t * y; - - this.set( - - tx * x + c, tx * y - s * z, tx * z + s * y, 0, - tx * y + s * z, ty * y + c, ty * z - s * x, 0, - tx * z - s * y, ty * z + s * x, t * z * z + c, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeScale( x, y, z ) { - - this.set( - - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - makeShear( xy, xz, yx, yz, zx, zy ) { - - this.set( - - 1, yx, zx, 0, - xy, 1, zy, 0, - xz, yz, 1, 0, - 0, 0, 0, 1 - - ); - - return this; - - } - - compose( position, quaternion, scale ) { - - const te = this.elements; - - const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; - const x2 = x + x, y2 = y + y, z2 = z + z; - const xx = x * x2, xy = x * y2, xz = x * z2; - const yy = y * y2, yz = y * z2, zz = z * z2; - const wx = w * x2, wy = w * y2, wz = w * z2; - - const sx = scale.x, sy = scale.y, sz = scale.z; - - te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; - te[ 1 ] = ( xy + wz ) * sx; - te[ 2 ] = ( xz - wy ) * sx; - te[ 3 ] = 0; - - te[ 4 ] = ( xy - wz ) * sy; - te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; - te[ 6 ] = ( yz + wx ) * sy; - te[ 7 ] = 0; - - te[ 8 ] = ( xz + wy ) * sz; - te[ 9 ] = ( yz - wx ) * sz; - te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; - te[ 11 ] = 0; - - te[ 12 ] = position.x; - te[ 13 ] = position.y; - te[ 14 ] = position.z; - te[ 15 ] = 1; - - return this; - - } - - decompose( position, quaternion, scale ) { - - const te = this.elements; - - let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); - const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); - const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); - - // if determine is negative, we need to invert one scale - const det = this.determinant(); - if ( det < 0 ) sx = - sx; - - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; - - // scale the rotation part - _m1$2.copy( this ); - - const invSX = 1 / sx; - const invSY = 1 / sy; - const invSZ = 1 / sz; - - _m1$2.elements[ 0 ] *= invSX; - _m1$2.elements[ 1 ] *= invSX; - _m1$2.elements[ 2 ] *= invSX; - - _m1$2.elements[ 4 ] *= invSY; - _m1$2.elements[ 5 ] *= invSY; - _m1$2.elements[ 6 ] *= invSY; - - _m1$2.elements[ 8 ] *= invSZ; - _m1$2.elements[ 9 ] *= invSZ; - _m1$2.elements[ 10 ] *= invSZ; - - quaternion.setFromRotationMatrix( _m1$2 ); - - scale.x = sx; - scale.y = sy; - scale.z = sz; - - return this; - - } - - makePerspective( left, right, top, bottom, near, far ) { - - if ( far === undefined ) { - - console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' ); - - } - - const te = this.elements; - const x = 2 * near / ( right - left ); - const y = 2 * near / ( top - bottom ); - - const a = ( right + left ) / ( right - left ); - const b = ( top + bottom ) / ( top - bottom ); - const c = - ( far + near ) / ( far - near ); - const d = - 2 * far * near / ( far - near ); - - te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; - te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; - - return this; - - } - - makeOrthographic( left, right, top, bottom, near, far ) { - - const te = this.elements; - const w = 1.0 / ( right - left ); - const h = 1.0 / ( top - bottom ); - const p = 1.0 / ( far - near ); - - const x = ( right + left ) * w; - const y = ( top + bottom ) * h; - const z = ( far + near ) * p; - - te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; - te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; - - return this; - - } - - equals( matrix ) { - - const te = this.elements; - const me = matrix.elements; - - for ( let i = 0; i < 16; i ++ ) { - - if ( te[ i ] !== me[ i ] ) return false; - - } - - return true; - - } - - fromArray( array, offset = 0 ) { - - for ( let i = 0; i < 16; i ++ ) { - - this.elements[ i ] = array[ i + offset ]; - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const te = this.elements; - - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - array[ offset + 3 ] = te[ 3 ]; - - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; - array[ offset + 10 ] = te[ 10 ]; - array[ offset + 11 ] = te[ 11 ]; - - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; - - return array; - - } - - } - - Matrix4.prototype.isMatrix4 = true; - - const _v1$5 = /*@__PURE__*/ new Vector3(); - const _m1$2 = /*@__PURE__*/ new Matrix4(); - const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); - const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); - const _x = /*@__PURE__*/ new Vector3(); - const _y = /*@__PURE__*/ new Vector3(); - const _z = /*@__PURE__*/ new Vector3(); - - const _matrix$1 = /*@__PURE__*/ new Matrix4(); - const _quaternion$3 = /*@__PURE__*/ new Quaternion(); - - class Euler { - - constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) { - - this._x = x; - this._y = y; - this._z = z; - this._order = order; - - } - - get x() { - - return this._x; - - } - - set x( value ) { - - this._x = value; - this._onChangeCallback(); - - } - - get y() { - - return this._y; - - } - - set y( value ) { - - this._y = value; - this._onChangeCallback(); - - } - - get z() { - - return this._z; - - } - - set z( value ) { - - this._z = value; - this._onChangeCallback(); - - } - - get order() { - - return this._order; - - } - - set order( value ) { - - this._order = value; - this._onChangeCallback(); - - } - - set( x, y, z, order = this._order ) { - - this._x = x; - this._y = y; - this._z = z; - this._order = order; - - this._onChangeCallback(); - - return this; - - } - - clone() { - - return new this.constructor( this._x, this._y, this._z, this._order ); - - } - - copy( euler ) { - - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; - - this._onChangeCallback(); - - return this; - - } - - setFromRotationMatrix( m, order = this._order, update = true ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - const te = m.elements; - const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; - const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; - const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - - switch ( order ) { - - case 'XYZ': - - this._y = Math.asin( clamp( m13, - 1, 1 ) ); - - if ( Math.abs( m13 ) < 0.9999999 ) { - - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); - - } else { - - this._x = Math.atan2( m32, m22 ); - this._z = 0; - - } - - break; - - case 'YXZ': - - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - - if ( Math.abs( m23 ) < 0.9999999 ) { - - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); - - } else { - - this._y = Math.atan2( - m31, m11 ); - this._z = 0; - - } - - break; - - case 'ZXY': - - this._x = Math.asin( clamp( m32, - 1, 1 ) ); - - if ( Math.abs( m32 ) < 0.9999999 ) { - - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); - - } else { - - this._y = 0; - this._z = Math.atan2( m21, m11 ); - - } - - break; - - case 'ZYX': - - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - - if ( Math.abs( m31 ) < 0.9999999 ) { - - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); - - } else { - - this._x = 0; - this._z = Math.atan2( - m12, m22 ); - - } - - break; - - case 'YZX': - - this._z = Math.asin( clamp( m21, - 1, 1 ) ); - - if ( Math.abs( m21 ) < 0.9999999 ) { - - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); - - } else { - - this._x = 0; - this._y = Math.atan2( m13, m33 ); - - } - - break; - - case 'XZY': - - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); - - if ( Math.abs( m12 ) < 0.9999999 ) { - - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); - - } else { - - this._x = Math.atan2( - m23, m33 ); - this._y = 0; - - } - - break; - - default: - - console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); - - } - - this._order = order; - - if ( update === true ) this._onChangeCallback(); - - return this; - - } - - setFromQuaternion( q, order, update ) { - - _matrix$1.makeRotationFromQuaternion( q ); - - return this.setFromRotationMatrix( _matrix$1, order, update ); - - } - - setFromVector3( v, order = this._order ) { - - return this.set( v.x, v.y, v.z, order ); - - } - - reorder( newOrder ) { - - // WARNING: this discards revolution information -bhouston - - _quaternion$3.setFromEuler( this ); - - return this.setFromQuaternion( _quaternion$3, newOrder ); - - } - - equals( euler ) { - - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); - - } - - fromArray( array ) { - - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; - - this._onChangeCallback(); - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; - - return array; - - } - - toVector3( optionalResult ) { - - if ( optionalResult ) { - - return optionalResult.set( this._x, this._y, this._z ); - - } else { - - return new Vector3( this._x, this._y, this._z ); - - } - - } - - _onChange( callback ) { - - this._onChangeCallback = callback; - - return this; - - } - - _onChangeCallback() {} - - } - - Euler.prototype.isEuler = true; - - Euler.DefaultOrder = 'XYZ'; - Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; - - class Layers { - - constructor() { - - this.mask = 1 | 0; - - } - - set( channel ) { - - this.mask = 1 << channel | 0; - - } - - enable( channel ) { - - this.mask |= 1 << channel | 0; - - } - - enableAll() { - - this.mask = 0xffffffff | 0; - - } - - toggle( channel ) { - - this.mask ^= 1 << channel | 0; - - } - - disable( channel ) { - - this.mask &= ~ ( 1 << channel | 0 ); - - } - - disableAll() { - - this.mask = 0; - - } - - test( layers ) { - - return ( this.mask & layers.mask ) !== 0; - - } - - } - - let _object3DId = 0; - - const _v1$4 = /*@__PURE__*/ new Vector3(); - const _q1 = /*@__PURE__*/ new Quaternion(); - const _m1$1 = /*@__PURE__*/ new Matrix4(); - const _target = /*@__PURE__*/ new Vector3(); - - const _position$3 = /*@__PURE__*/ new Vector3(); - const _scale$2 = /*@__PURE__*/ new Vector3(); - const _quaternion$2 = /*@__PURE__*/ new Quaternion(); - - const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); - const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); - - const _addedEvent = { type: 'added' }; - const _removedEvent = { type: 'removed' }; - - class Object3D extends EventDispatcher { - - constructor() { - - super(); - - Object.defineProperty( this, 'id', { value: _object3DId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'Object3D'; - - this.parent = null; - this.children = []; - - this.up = Object3D.DefaultUp.clone(); - - const position = new Vector3(); - const rotation = new Euler(); - const quaternion = new Quaternion(); - const scale = new Vector3( 1, 1, 1 ); - - function onRotationChange() { - - quaternion.setFromEuler( rotation, false ); - - } - - function onQuaternionChange() { - - rotation.setFromQuaternion( quaternion, undefined, false ); - - } - - rotation._onChange( onRotationChange ); - quaternion._onChange( onQuaternionChange ); - - Object.defineProperties( this, { - position: { - configurable: true, - enumerable: true, - value: position - }, - rotation: { - configurable: true, - enumerable: true, - value: rotation - }, - quaternion: { - configurable: true, - enumerable: true, - value: quaternion - }, - scale: { - configurable: true, - enumerable: true, - value: scale - }, - modelViewMatrix: { - value: new Matrix4() - }, - normalMatrix: { - value: new Matrix3() - } - } ); - - this.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); - - this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; - this.matrixWorldNeedsUpdate = false; - - this.layers = new Layers(); - this.visible = true; - - this.castShadow = false; - this.receiveShadow = false; - - this.frustumCulled = true; - this.renderOrder = 0; - - this.animations = []; - - this.userData = {}; - - } - - onBeforeRender() {} - onAfterRender() {} - - applyMatrix4( matrix ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - this.matrix.premultiply( matrix ); - - this.matrix.decompose( this.position, this.quaternion, this.scale ); - - } - - applyQuaternion( q ) { - - this.quaternion.premultiply( q ); - - return this; - - } - - setRotationFromAxisAngle( axis, angle ) { - - // assumes axis is normalized - - this.quaternion.setFromAxisAngle( axis, angle ); - - } - - setRotationFromEuler( euler ) { - - this.quaternion.setFromEuler( euler, true ); - - } - - setRotationFromMatrix( m ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - - this.quaternion.setFromRotationMatrix( m ); - - } - - setRotationFromQuaternion( q ) { - - // assumes q is normalized - - this.quaternion.copy( q ); - - } - - rotateOnAxis( axis, angle ) { - - // rotate object on axis in object space - // axis is assumed to be normalized - - _q1.setFromAxisAngle( axis, angle ); - - this.quaternion.multiply( _q1 ); - - return this; - - } - - rotateOnWorldAxis( axis, angle ) { - - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent - - _q1.setFromAxisAngle( axis, angle ); - - this.quaternion.premultiply( _q1 ); - - return this; - - } - - rotateX( angle ) { - - return this.rotateOnAxis( _xAxis, angle ); - - } - - rotateY( angle ) { - - return this.rotateOnAxis( _yAxis, angle ); - - } - - rotateZ( angle ) { - - return this.rotateOnAxis( _zAxis, angle ); - - } - - translateOnAxis( axis, distance ) { - - // translate object by distance along axis in object space - // axis is assumed to be normalized - - _v1$4.copy( axis ).applyQuaternion( this.quaternion ); - - this.position.add( _v1$4.multiplyScalar( distance ) ); - - return this; - - } - - translateX( distance ) { - - return this.translateOnAxis( _xAxis, distance ); - - } - - translateY( distance ) { - - return this.translateOnAxis( _yAxis, distance ); - - } - - translateZ( distance ) { - - return this.translateOnAxis( _zAxis, distance ); - - } - - localToWorld( vector ) { - - return vector.applyMatrix4( this.matrixWorld ); - - } - - worldToLocal( vector ) { - - return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); - - } - - lookAt( x, y, z ) { - - // This method does not support objects having non-uniformly-scaled parent(s) - - if ( x.isVector3 ) { - - _target.copy( x ); - - } else { - - _target.set( x, y, z ); - - } - - const parent = this.parent; - - this.updateWorldMatrix( true, false ); - - _position$3.setFromMatrixPosition( this.matrixWorld ); - - if ( this.isCamera || this.isLight ) { - - _m1$1.lookAt( _position$3, _target, this.up ); - - } else { - - _m1$1.lookAt( _target, _position$3, this.up ); - - } - - this.quaternion.setFromRotationMatrix( _m1$1 ); - - if ( parent ) { - - _m1$1.extractRotation( parent.matrixWorld ); - _q1.setFromRotationMatrix( _m1$1 ); - this.quaternion.premultiply( _q1.invert() ); - - } - - } - - add( object ) { - - if ( arguments.length > 1 ) { - - for ( let i = 0; i < arguments.length; i ++ ) { - - this.add( arguments[ i ] ); - - } - - return this; - - } - - if ( object === this ) { - - console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); - return this; - - } - - if ( object && object.isObject3D ) { - - if ( object.parent !== null ) { - - object.parent.remove( object ); - - } - - object.parent = this; - this.children.push( object ); - - object.dispatchEvent( _addedEvent ); - - } else { - - console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); - - } - - return this; - - } - - remove( object ) { - - if ( arguments.length > 1 ) { - - for ( let i = 0; i < arguments.length; i ++ ) { - - this.remove( arguments[ i ] ); - - } - - return this; - - } - - const index = this.children.indexOf( object ); - - if ( index !== - 1 ) { - - object.parent = null; - this.children.splice( index, 1 ); - - object.dispatchEvent( _removedEvent ); - - } - - return this; - - } - - removeFromParent() { - - const parent = this.parent; - - if ( parent !== null ) { - - parent.remove( this ); - - } - - return this; - - } - - clear() { - - for ( let i = 0; i < this.children.length; i ++ ) { - - const object = this.children[ i ]; - - object.parent = null; - - object.dispatchEvent( _removedEvent ); - - } - - this.children.length = 0; - - return this; - - - } - - attach( object ) { - - // adds object as a child of this, while maintaining the object's world transform - - this.updateWorldMatrix( true, false ); - - _m1$1.copy( this.matrixWorld ).invert(); - - if ( object.parent !== null ) { - - object.parent.updateWorldMatrix( true, false ); - - _m1$1.multiply( object.parent.matrixWorld ); - - } - - object.applyMatrix4( _m1$1 ); - - this.add( object ); - - object.updateWorldMatrix( false, true ); - - return this; - - } - - getObjectById( id ) { - - return this.getObjectByProperty( 'id', id ); - - } - - getObjectByName( name ) { - - return this.getObjectByProperty( 'name', name ); - - } - - getObjectByProperty( name, value ) { - - if ( this[ name ] === value ) return this; - - for ( let i = 0, l = this.children.length; i < l; i ++ ) { - - const child = this.children[ i ]; - const object = child.getObjectByProperty( name, value ); - - if ( object !== undefined ) { - - return object; - - } - - } - - return undefined; - - } - - getWorldPosition( target ) { - - this.updateWorldMatrix( true, false ); - - return target.setFromMatrixPosition( this.matrixWorld ); - - } - - getWorldQuaternion( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, target, _scale$2 ); - - return target; - - } - - getWorldScale( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, _quaternion$2, target ); - - return target; - - } - - getWorldDirection( target ) { - - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; - - return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); - - } - - raycast() {} - - traverse( callback ) { - - callback( this ); - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].traverse( callback ); - - } - - } - - traverseVisible( callback ) { - - if ( this.visible === false ) return; - - callback( this ); - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].traverseVisible( callback ); - - } - - } - - traverseAncestors( callback ) { - - const parent = this.parent; - - if ( parent !== null ) { - - callback( parent ); - - parent.traverseAncestors( callback ); - - } - - } - - updateMatrix() { - - this.matrix.compose( this.position, this.quaternion, this.scale ); - - this.matrixWorldNeedsUpdate = true; - - } - - updateMatrixWorld( force ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.matrixWorldNeedsUpdate || force ) { - - if ( this.parent === null ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - this.matrixWorldNeedsUpdate = false; - - force = true; - - } - - // update children - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].updateMatrixWorld( force ); - - } - - } - - updateWorldMatrix( updateParents, updateChildren ) { - - const parent = this.parent; - - if ( updateParents === true && parent !== null ) { - - parent.updateWorldMatrix( true, false ); - - } - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.parent === null ) { - - this.matrixWorld.copy( this.matrix ); - - } else { - - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - - } - - // update children - - if ( updateChildren === true ) { - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].updateWorldMatrix( false, true ); - - } - - } - - } - - toJSON( meta ) { - - // meta is a string when called from JSON.stringify - const isRootObject = ( meta === undefined || typeof meta === 'string' ); - - const output = {}; - - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { - - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {}, - shapes: {}, - skeletons: {}, - animations: {} - }; - - output.metadata = { - version: 4.5, - type: 'Object', - generator: 'Object3D.toJSON' - }; - - } - - // standard Object3D serialization - - const object = {}; - - object.uuid = this.uuid; - object.type = this.type; - - if ( this.name !== '' ) object.name = this.name; - if ( this.castShadow === true ) object.castShadow = true; - if ( this.receiveShadow === true ) object.receiveShadow = true; - if ( this.visible === false ) object.visible = false; - if ( this.frustumCulled === false ) object.frustumCulled = false; - if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; - if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; - - object.layers = this.layers.mask; - object.matrix = this.matrix.toArray(); - - if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; - - // object specific properties - - if ( this.isInstancedMesh ) { - - object.type = 'InstancedMesh'; - object.count = this.count; - object.instanceMatrix = this.instanceMatrix.toJSON(); - if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); - - } - - // - - function serialize( library, element ) { - - if ( library[ element.uuid ] === undefined ) { - - library[ element.uuid ] = element.toJSON( meta ); - - } - - return element.uuid; - - } - - if ( this.isScene ) { - - if ( this.background ) { - - if ( this.background.isColor ) { - - object.background = this.background.toJSON(); - - } else if ( this.background.isTexture ) { - - object.background = this.background.toJSON( meta ).uuid; - - } - - } - - if ( this.environment && this.environment.isTexture ) { - - object.environment = this.environment.toJSON( meta ).uuid; - - } - - } else if ( this.isMesh || this.isLine || this.isPoints ) { - - object.geometry = serialize( meta.geometries, this.geometry ); - - const parameters = this.geometry.parameters; - - if ( parameters !== undefined && parameters.shapes !== undefined ) { - - const shapes = parameters.shapes; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - serialize( meta.shapes, shape ); - - } - - } else { - - serialize( meta.shapes, shapes ); - - } - - } - - } - - if ( this.isSkinnedMesh ) { - - object.bindMode = this.bindMode; - object.bindMatrix = this.bindMatrix.toArray(); - - if ( this.skeleton !== undefined ) { - - serialize( meta.skeletons, this.skeleton ); - - object.skeleton = this.skeleton.uuid; - - } - - } - - if ( this.material !== undefined ) { - - if ( Array.isArray( this.material ) ) { - - const uuids = []; - - for ( let i = 0, l = this.material.length; i < l; i ++ ) { - - uuids.push( serialize( meta.materials, this.material[ i ] ) ); - - } - - object.material = uuids; - - } else { - - object.material = serialize( meta.materials, this.material ); - - } - - } - - // - - if ( this.children.length > 0 ) { - - object.children = []; - - for ( let i = 0; i < this.children.length; i ++ ) { - - object.children.push( this.children[ i ].toJSON( meta ).object ); - - } - - } - - // - - if ( this.animations.length > 0 ) { - - object.animations = []; - - for ( let i = 0; i < this.animations.length; i ++ ) { - - const animation = this.animations[ i ]; - - object.animations.push( serialize( meta.animations, animation ) ); - - } - - } - - if ( isRootObject ) { - - const geometries = extractFromCache( meta.geometries ); - const materials = extractFromCache( meta.materials ); - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const shapes = extractFromCache( meta.shapes ); - const skeletons = extractFromCache( meta.skeletons ); - const animations = extractFromCache( meta.animations ); - - 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; - if ( skeletons.length > 0 ) output.skeletons = skeletons; - if ( animations.length > 0 ) output.animations = animations; - - } - - output.object = object; - - return output; - - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { - - const values = []; - for ( const key in cache ) { - - const data = cache[ key ]; - delete data.metadata; - values.push( data ); - - } - - return values; - - } - - } - - clone( recursive ) { - - return new this.constructor().copy( this, recursive ); - - } - - copy( source, recursive = true ) { - - this.name = source.name; - - this.up.copy( source.up ); - - this.position.copy( source.position ); - this.rotation.order = source.rotation.order; - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); - - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); - - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - - this.layers.mask = source.layers.mask; - this.visible = source.visible; - - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; - - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - if ( recursive === true ) { - - for ( let i = 0; i < source.children.length; i ++ ) { - - const child = source.children[ i ]; - this.add( child.clone() ); - - } - - } - - return this; - - } - - } - - Object3D.DefaultUp = new Vector3( 0, 1, 0 ); - Object3D.DefaultMatrixAutoUpdate = true; - - Object3D.prototype.isObject3D = true; - - const _v0$1 = /*@__PURE__*/ new Vector3(); - const _v1$3 = /*@__PURE__*/ new Vector3(); - const _v2$2 = /*@__PURE__*/ new Vector3(); - const _v3$1 = /*@__PURE__*/ new Vector3(); - - const _vab = /*@__PURE__*/ new Vector3(); - const _vac = /*@__PURE__*/ new Vector3(); - const _vbc = /*@__PURE__*/ new Vector3(); - const _vap = /*@__PURE__*/ new Vector3(); - const _vbp = /*@__PURE__*/ new Vector3(); - const _vcp = /*@__PURE__*/ new Vector3(); - - class Triangle { - - constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { - - this.a = a; - this.b = b; - this.c = c; - - } - - static getNormal( a, b, c, target ) { - - target.subVectors( c, b ); - _v0$1.subVectors( a, b ); - target.cross( _v0$1 ); - - const targetLengthSq = target.lengthSq(); - if ( targetLengthSq > 0 ) { - - return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); - - } - - return target.set( 0, 0, 0 ); - - } - - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - static getBarycoord( point, a, b, c, target ) { - - _v0$1.subVectors( c, a ); - _v1$3.subVectors( b, a ); - _v2$2.subVectors( point, a ); - - const dot00 = _v0$1.dot( _v0$1 ); - const dot01 = _v0$1.dot( _v1$3 ); - const dot02 = _v0$1.dot( _v2$2 ); - const dot11 = _v1$3.dot( _v1$3 ); - const dot12 = _v1$3.dot( _v2$2 ); - - const denom = ( dot00 * dot11 - dot01 * dot01 ); - - // collinear or singular triangle - if ( denom === 0 ) { - - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return target.set( - 2, - 1, - 1 ); - - } - - const invDenom = 1 / denom; - const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - - // barycentric coordinates must always sum to 1 - return target.set( 1 - u - v, v, u ); - - } - - static containsPoint( point, a, b, c ) { - - this.getBarycoord( point, a, b, c, _v3$1 ); - - return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); - - } - - static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { - - this.getBarycoord( point, p1, p2, p3, _v3$1 ); - - target.set( 0, 0 ); - target.addScaledVector( uv1, _v3$1.x ); - target.addScaledVector( uv2, _v3$1.y ); - target.addScaledVector( uv3, _v3$1.z ); - - return target; - - } - - static isFrontFacing( a, b, c, direction ) { - - _v0$1.subVectors( c, b ); - _v1$3.subVectors( a, b ); - - // strictly front facing - return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; - - } - - set( a, b, c ) { - - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); - - return this; - - } - - setFromPointsAndIndices( points, i0, i1, i2 ) { - - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( triangle ) { - - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); - - return this; - - } - - getArea() { - - _v0$1.subVectors( this.c, this.b ); - _v1$3.subVectors( this.a, this.b ); - - return _v0$1.cross( _v1$3 ).length() * 0.5; - - } - - getMidpoint( target ) { - - return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - - } - - getNormal( target ) { - - return Triangle.getNormal( this.a, this.b, this.c, target ); - - } - - getPlane( target ) { - - return target.setFromCoplanarPoints( this.a, this.b, this.c ); - - } - - getBarycoord( point, target ) { - - return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); - - } - - getUV( point, uv1, uv2, uv3, target ) { - - return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); - - } - - containsPoint( point ) { - - return Triangle.containsPoint( point, this.a, this.b, this.c ); - - } - - isFrontFacing( direction ) { - - return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); - - } - - intersectsBox( box ) { - - return box.intersectsTriangle( this ); - - } - - closestPointToPoint( p, target ) { - - const a = this.a, b = this.b, c = this.c; - let v, w; - - // algorithm thanks to Real-Time Collision Detection by Christer Ericson, - // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., - // under the accompanying license; see chapter 5.1.5 for detailed explanation. - // basically, we're distinguishing which of the voronoi regions of the triangle - // the point lies in with the minimum amount of redundant computation. - - _vab.subVectors( b, a ); - _vac.subVectors( c, a ); - _vap.subVectors( p, a ); - const d1 = _vab.dot( _vap ); - const d2 = _vac.dot( _vap ); - if ( d1 <= 0 && d2 <= 0 ) { - - // vertex region of A; barycentric coords (1, 0, 0) - return target.copy( a ); - - } - - _vbp.subVectors( p, b ); - const d3 = _vab.dot( _vbp ); - const d4 = _vac.dot( _vbp ); - if ( d3 >= 0 && d4 <= d3 ) { - - // vertex region of B; barycentric coords (0, 1, 0) - return target.copy( b ); - - } - - const vc = d1 * d4 - d3 * d2; - if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { - - v = d1 / ( d1 - d3 ); - // edge region of AB; barycentric coords (1-v, v, 0) - return target.copy( a ).addScaledVector( _vab, v ); - - } - - _vcp.subVectors( p, c ); - const d5 = _vab.dot( _vcp ); - const d6 = _vac.dot( _vcp ); - if ( d6 >= 0 && d5 <= d6 ) { - - // vertex region of C; barycentric coords (0, 0, 1) - return target.copy( c ); - - } - - const vb = d5 * d2 - d1 * d6; - if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - - w = d2 / ( d2 - d6 ); - // edge region of AC; barycentric coords (1-w, 0, w) - return target.copy( a ).addScaledVector( _vac, w ); - - } - - const va = d3 * d6 - d5 * d4; - if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - - _vbc.subVectors( c, b ); - w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); - // edge region of BC; barycentric coords (0, 1-w, w) - return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC - - } - - // face region - const denom = 1 / ( va + vb + vc ); - // u = va * denom - v = vb * denom; - w = vc * denom; - - return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); - - } - - equals( triangle ) { - - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - - } - - } - - let materialId = 0; - - class Material extends EventDispatcher { - - constructor() { - - super(); - - Object.defineProperty( this, 'id', { value: materialId ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'Material'; - - this.fog = true; - - this.blending = NormalBlending; - this.side = FrontSide; - this.vertexColors = false; - - this.opacity = 1; - this.format = RGBAFormat; - this.transparent = false; - - this.blendSrc = SrcAlphaFactor; - this.blendDst = OneMinusSrcAlphaFactor; - this.blendEquation = AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; - - this.depthFunc = LessEqualDepth; - this.depthTest = true; - this.depthWrite = true; - - this.stencilWriteMask = 0xff; - this.stencilFunc = AlwaysStencilFunc; - this.stencilRef = 0; - this.stencilFuncMask = 0xff; - this.stencilFail = KeepStencilOp; - this.stencilZFail = KeepStencilOp; - this.stencilZPass = KeepStencilOp; - this.stencilWrite = false; - - this.clippingPlanes = null; - this.clipIntersection = false; - this.clipShadows = false; - - this.shadowSide = null; - - this.colorWrite = true; - - this.precision = null; // override the renderer's default precision for this material - - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; - - this.dithering = false; - - this.alphaToCoverage = false; - this.premultipliedAlpha = false; - - this.visible = true; - - this.toneMapped = true; - - this.userData = {}; - - this.version = 0; - - this._alphaTest = 0; - - } - - get alphaTest() { - - return this._alphaTest; - - } - - set alphaTest( value ) { - - if ( this._alphaTest > 0 !== value > 0 ) { - - this.version ++; - - } - - this._alphaTest = value; - - } - - onBuild( /* shaderobject, renderer */ ) {} - - onBeforeCompile( /* shaderobject, renderer */ ) {} - - customProgramCacheKey() { - - return this.onBeforeCompile.toString(); - - } - - setValues( values ) { - - if ( values === undefined ) return; - - for ( const key in values ) { - - const newValue = values[ key ]; - - if ( newValue === undefined ) { - - console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); - continue; - - } - - // for backward compatability if shading is set in the constructor - if ( key === 'shading' ) { - - console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); - this.flatShading = ( newValue === FlatShading ) ? true : false; - continue; - - } - - const currentValue = this[ key ]; - - if ( currentValue === undefined ) { - - console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' ); - continue; - - } - - if ( currentValue && currentValue.isColor ) { - - currentValue.set( newValue ); - - } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { - - currentValue.copy( newValue ); - - } else { - - this[ key ] = newValue; - - } - - } - - } - - toJSON( meta ) { - - const isRoot = ( meta === undefined || typeof meta === 'string' ); - - if ( isRoot ) { - - meta = { - textures: {}, - images: {} - }; - - } - - const data = { - metadata: { - version: 4.5, - type: 'Material', - generator: 'Material.toJSON' - } - }; - - // standard Material serialization - data.uuid = this.uuid; - data.type = this.type; - - if ( this.name !== '' ) data.name = this.name; - - if ( this.color && this.color.isColor ) data.color = this.color.getHex(); - - if ( this.roughness !== undefined ) data.roughness = this.roughness; - if ( this.metalness !== undefined ) data.metalness = this.metalness; - - if ( this.sheenTint && this.sheenTint.isColor ) data.sheenTint = this.sheenTint.getHex(); - if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); - if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; - - if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); - if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; - if ( this.specularTint && this.specularTint.isColor ) data.specularTint = this.specularTint.getHex(); - if ( this.shininess !== undefined ) data.shininess = this.shininess; - if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; - if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; - - if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { - - data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; - - } - - if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { - - data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; - - } - - if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { - - data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; - data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); - - } - - if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; - if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; - if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; - - if ( this.lightMap && this.lightMap.isTexture ) { - - data.lightMap = this.lightMap.toJSON( meta ).uuid; - data.lightMapIntensity = this.lightMapIntensity; - - } - - if ( this.aoMap && this.aoMap.isTexture ) { - - data.aoMap = this.aoMap.toJSON( meta ).uuid; - data.aoMapIntensity = this.aoMapIntensity; - - } - - if ( this.bumpMap && this.bumpMap.isTexture ) { - - data.bumpMap = this.bumpMap.toJSON( meta ).uuid; - data.bumpScale = this.bumpScale; - - } - - if ( this.normalMap && this.normalMap.isTexture ) { - - data.normalMap = this.normalMap.toJSON( meta ).uuid; - data.normalMapType = this.normalMapType; - data.normalScale = this.normalScale.toArray(); - - } - - if ( this.displacementMap && this.displacementMap.isTexture ) { - - data.displacementMap = this.displacementMap.toJSON( meta ).uuid; - data.displacementScale = this.displacementScale; - data.displacementBias = this.displacementBias; - - } - - if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; - if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; - - if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; - if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; - if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; - if ( this.specularTintMap && this.specularTintMap.isTexture ) data.specularTintMap = this.specularTintMap.toJSON( meta ).uuid; - - if ( this.envMap && this.envMap.isTexture ) { - - data.envMap = this.envMap.toJSON( meta ).uuid; - - if ( this.combine !== undefined ) data.combine = this.combine; - - } - - if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; - if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; - if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; - - if ( this.gradientMap && this.gradientMap.isTexture ) { - - data.gradientMap = this.gradientMap.toJSON( meta ).uuid; - - } - - if ( this.transmission !== undefined ) data.transmission = this.transmission; - if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; - if ( this.thickness !== undefined ) data.thickness = this.thickness; - if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; - if ( this.attenuationDistance !== undefined ) data.attenuationDistance = this.attenuationDistance; - if ( this.attenuationTint !== undefined ) data.attenuationTint = this.attenuationTint.getHex(); - - if ( this.size !== undefined ) data.size = this.size; - if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; - if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; - - if ( this.blending !== NormalBlending ) data.blending = this.blending; - if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors ) data.vertexColors = true; - - if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.format !== RGBAFormat ) data.format = this.format; - if ( this.transparent === true ) data.transparent = this.transparent; - - data.depthFunc = this.depthFunc; - data.depthTest = this.depthTest; - data.depthWrite = this.depthWrite; - data.colorWrite = this.colorWrite; - - data.stencilWrite = this.stencilWrite; - data.stencilWriteMask = this.stencilWriteMask; - data.stencilFunc = this.stencilFunc; - data.stencilRef = this.stencilRef; - data.stencilFuncMask = this.stencilFuncMask; - data.stencilFail = this.stencilFail; - data.stencilZFail = this.stencilZFail; - data.stencilZPass = this.stencilZPass; - - // rotation (SpriteMaterial) - if ( this.rotation && this.rotation !== 0 ) data.rotation = this.rotation; - - if ( this.polygonOffset === true ) data.polygonOffset = true; - if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; - if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; - - if ( this.linewidth && this.linewidth !== 1 ) data.linewidth = this.linewidth; - if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; - if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; - if ( this.scale !== undefined ) data.scale = this.scale; - - if ( this.dithering === true ) data.dithering = true; - - if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.alphaToCoverage === true ) data.alphaToCoverage = this.alphaToCoverage; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; - - if ( this.wireframe === true ) data.wireframe = this.wireframe; - if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; - if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; - if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; - - if ( this.flatShading === true ) data.flatShading = this.flatShading; - - if ( this.visible === false ) data.visible = false; - - if ( this.toneMapped === false ) data.toneMapped = false; - - if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; - - // TODO: Copied from Object3D.toJSON - - function extractFromCache( cache ) { - - const values = []; - - for ( const key in cache ) { - - const data = cache[ key ]; - delete data.metadata; - values.push( data ); - - } - - return values; - - } - - if ( isRoot ) { - - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; - - } - - return data; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.name = source.name; - - this.fog = source.fog; - - this.blending = source.blending; - this.side = source.side; - this.vertexColors = source.vertexColors; - - this.opacity = source.opacity; - this.format = source.format; - this.transparent = source.transparent; - - this.blendSrc = source.blendSrc; - this.blendDst = source.blendDst; - this.blendEquation = source.blendEquation; - this.blendSrcAlpha = source.blendSrcAlpha; - this.blendDstAlpha = source.blendDstAlpha; - this.blendEquationAlpha = source.blendEquationAlpha; - - this.depthFunc = source.depthFunc; - this.depthTest = source.depthTest; - this.depthWrite = source.depthWrite; - - this.stencilWriteMask = source.stencilWriteMask; - this.stencilFunc = source.stencilFunc; - this.stencilRef = source.stencilRef; - this.stencilFuncMask = source.stencilFuncMask; - this.stencilFail = source.stencilFail; - this.stencilZFail = source.stencilZFail; - this.stencilZPass = source.stencilZPass; - this.stencilWrite = source.stencilWrite; - - const srcPlanes = source.clippingPlanes; - let dstPlanes = null; - - if ( srcPlanes !== null ) { - - const n = srcPlanes.length; - dstPlanes = new Array( n ); - - for ( let i = 0; i !== n; ++ i ) { - - dstPlanes[ i ] = srcPlanes[ i ].clone(); - - } - - } - - this.clippingPlanes = dstPlanes; - this.clipIntersection = source.clipIntersection; - this.clipShadows = source.clipShadows; - - this.shadowSide = source.shadowSide; - - this.colorWrite = source.colorWrite; - - this.precision = source.precision; - - this.polygonOffset = source.polygonOffset; - this.polygonOffsetFactor = source.polygonOffsetFactor; - this.polygonOffsetUnits = source.polygonOffsetUnits; - - this.dithering = source.dithering; - - this.alphaTest = source.alphaTest; - this.alphaToCoverage = source.alphaToCoverage; - this.premultipliedAlpha = source.premultipliedAlpha; - - this.visible = source.visible; - - this.toneMapped = source.toneMapped; - - this.userData = JSON.parse( JSON.stringify( source.userData ) ); - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - } - - Material.prototype.isMaterial = true; - - const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - - const _hslA = { h: 0, s: 0, l: 0 }; - const _hslB = { h: 0, s: 0, l: 0 }; - - function hue2rgb( p, q, t ) { - - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; - - } - - function SRGBToLinear( c ) { - - return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); - - } - - function LinearToSRGB( c ) { - - return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; - - } - - class Color { - - constructor( r, g, b ) { - - if ( g === undefined && b === undefined ) { - - // r is THREE.Color, hex or string - return this.set( r ); - - } - - return this.setRGB( r, g, b ); - - } - - set( value ) { - - if ( value && value.isColor ) { - - this.copy( value ); - - } else if ( typeof value === 'number' ) { - - this.setHex( value ); - - } else if ( typeof value === 'string' ) { - - this.setStyle( value ); - - } - - return this; - - } - - setScalar( scalar ) { - - this.r = scalar; - this.g = scalar; - this.b = scalar; - - return this; - - } - - setHex( hex ) { - - hex = Math.floor( hex ); - - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; - - return this; - - } - - setRGB( r, g, b ) { - - this.r = r; - this.g = g; - this.b = b; - - return this; - - } - - setHSL( h, s, l ) { - - // h,s,l ranges are in 0.0 - 1.0 - h = euclideanModulo( h, 1 ); - s = clamp( s, 0, 1 ); - l = clamp( l, 0, 1 ); - - if ( s === 0 ) { - - this.r = this.g = this.b = l; - - } else { - - const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - const q = ( 2 * l ) - p; - - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); - - } - - return this; - - } - - setStyle( style ) { - - function handleAlpha( string ) { - - if ( string === undefined ) return; - - if ( parseFloat( string ) < 1 ) { - - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); - - } - - } - - - let m; - - if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) { - - // rgb / hsl - - let color; - const name = m[ 1 ]; - const components = m[ 2 ]; - - switch ( name ) { - - case 'rgb': - case 'rgba': - - if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // rgb(255,0,0) rgba(255,0,0,0.5) - this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; - this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; - this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; - - handleAlpha( color[ 4 ] ); - - return this; - - } - - if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) - this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; - this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; - this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; - - handleAlpha( color[ 4 ] ); - - return this; - - } - - break; - - case 'hsl': - case 'hsla': - - if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - - // hsl(120,50%,50%) hsla(120,50%,50%,0.5) - const h = parseFloat( color[ 1 ] ) / 360; - const s = parseInt( color[ 2 ], 10 ) / 100; - const l = parseInt( color[ 3 ], 10 ) / 100; - - handleAlpha( color[ 4 ] ); - - return this.setHSL( h, s, l ); - - } - - break; - - } - - } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { - - // hex color - - const hex = m[ 1 ]; - const size = hex.length; - - if ( size === 3 ) { - - // #ff0 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; - - return this; - - } else if ( size === 6 ) { - - // #ff0000 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; - - return this; - - } - - } - - if ( style && style.length > 0 ) { - - return this.setColorName( style ); - - } - - return this; - - } - - setColorName( style ) { - - // color keywords - const hex = _colorKeywords[ style.toLowerCase() ]; - - if ( hex !== undefined ) { - - // red - this.setHex( hex ); - - } else { - - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); - - } - - return this; - - } - - clone() { - - return new this.constructor( this.r, this.g, this.b ); - - } - - copy( color ) { - - this.r = color.r; - this.g = color.g; - this.b = color.b; - - return this; - - } - - copyGammaToLinear( color, gammaFactor = 2.0 ) { - - this.r = Math.pow( color.r, gammaFactor ); - this.g = Math.pow( color.g, gammaFactor ); - this.b = Math.pow( color.b, gammaFactor ); - - return this; - - } - - copyLinearToGamma( color, gammaFactor = 2.0 ) { - - const safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; - - this.r = Math.pow( color.r, safeInverse ); - this.g = Math.pow( color.g, safeInverse ); - this.b = Math.pow( color.b, safeInverse ); - - return this; - - } - - convertGammaToLinear( gammaFactor ) { - - this.copyGammaToLinear( this, gammaFactor ); - - return this; - - } - - convertLinearToGamma( gammaFactor ) { - - this.copyLinearToGamma( this, gammaFactor ); - - return this; - - } - - copySRGBToLinear( color ) { - - this.r = SRGBToLinear( color.r ); - this.g = SRGBToLinear( color.g ); - this.b = SRGBToLinear( color.b ); - - return this; - - } - - copyLinearToSRGB( color ) { - - this.r = LinearToSRGB( color.r ); - this.g = LinearToSRGB( color.g ); - this.b = LinearToSRGB( color.b ); - - return this; - - } - - convertSRGBToLinear() { - - this.copySRGBToLinear( this ); - - return this; - - } - - convertLinearToSRGB() { - - this.copyLinearToSRGB( this ); - - return this; - - } - - getHex() { - - return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; - - } - - getHexString() { - - return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); - - } - - getHSL( target ) { - - // h,s,l ranges are in 0.0 - 1.0 - - const r = this.r, g = this.g, b = this.b; - - const max = Math.max( r, g, b ); - const min = Math.min( r, g, b ); - - let hue, saturation; - const lightness = ( min + max ) / 2.0; - - if ( min === max ) { - - hue = 0; - saturation = 0; - - } else { - - const delta = max - min; - - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - - switch ( max ) { - - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; - - } - - hue /= 6; - - } - - target.h = hue; - target.s = saturation; - target.l = lightness; - - return target; - - } - - getStyle() { - - return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; - - } - - offsetHSL( h, s, l ) { - - this.getHSL( _hslA ); - - _hslA.h += h; _hslA.s += s; _hslA.l += l; - - this.setHSL( _hslA.h, _hslA.s, _hslA.l ); - - return this; - - } - - add( color ) { - - this.r += color.r; - this.g += color.g; - this.b += color.b; - - return this; - - } - - addColors( color1, color2 ) { - - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; - - return this; - - } - - addScalar( s ) { - - this.r += s; - this.g += s; - this.b += s; - - return this; - - } - - sub( color ) { - - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); - - return this; - - } - - multiply( color ) { - - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; - - return this; - - } - - multiplyScalar( s ) { - - this.r *= s; - this.g *= s; - this.b *= s; - - return this; - - } - - lerp( color, alpha ) { - - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; - - return this; - - } - - lerpColors( color1, color2, alpha ) { - - this.r = color1.r + ( color2.r - color1.r ) * alpha; - this.g = color1.g + ( color2.g - color1.g ) * alpha; - this.b = color1.b + ( color2.b - color1.b ) * alpha; - - return this; - - } - - lerpHSL( color, alpha ) { - - this.getHSL( _hslA ); - color.getHSL( _hslB ); - - const h = lerp$2( _hslA.h, _hslB.h, alpha ); - const s = lerp$2( _hslA.s, _hslB.s, alpha ); - const l = lerp$2( _hslA.l, _hslB.l, alpha ); - - this.setHSL( h, s, l ); - - return this; - - } - - equals( c ) { - - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - - } - - fromArray( array, offset = 0 ) { - - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; - - return this; - - } - - toArray( array = [], offset = 0 ) { - - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; - - return array; - - } - - fromBufferAttribute( attribute, index ) { - - this.r = attribute.getX( index ); - this.g = attribute.getY( index ); - this.b = attribute.getZ( index ); - - if ( attribute.normalized === true ) { - - // assuming Uint8Array - - this.r /= 255; - this.g /= 255; - this.b /= 255; - - } - - return this; - - } - - toJSON() { - - return this.getHex(); - - } - - } - - Color.NAMES = _colorKeywords; - - Color.prototype.isColor = true; - Color.prototype.r = 1; - Color.prototype.g = 1; - Color.prototype.b = 1; - - /** - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * specularMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * depthTest: , - * depthWrite: , - * - * wireframe: , - * wireframeLinewidth: , - * } - */ - - class MeshBasicMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'MeshBasicMaterial'; - - this.color = new Color( 0xffffff ); // emissive - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - return this; - - } - - } - - MeshBasicMaterial.prototype.isMeshBasicMaterial = true; - - const _vector$9 = /*@__PURE__*/ new Vector3(); - const _vector2$1 = /*@__PURE__*/ new Vector2(); - - class BufferAttribute { - - constructor( array, itemSize, normalized ) { - - if ( Array.isArray( array ) ) { - - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - - } - - this.name = ''; - - this.array = array; - this.itemSize = itemSize; - this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized === true; - - this.usage = StaticDrawUsage; - this.updateRange = { offset: 0, count: - 1 }; - - this.version = 0; - - } - - onUploadCallback() {} - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - setUsage( value ) { - - this.usage = value; - - return this; - - } - - copy( source ) { - - this.name = source.name; - this.array = new source.array.constructor( source.array ); - this.itemSize = source.itemSize; - this.count = source.count; - this.normalized = source.normalized; - - this.usage = source.usage; - - return this; - - } - - copyAt( index1, attribute, index2 ) { - - index1 *= this.itemSize; - index2 *= attribute.itemSize; - - for ( let i = 0, l = this.itemSize; i < l; i ++ ) { - - this.array[ index1 + i ] = attribute.array[ index2 + i ]; - - } - - return this; - - } - - copyArray( array ) { - - this.array.set( array ); - - return this; - - } - - copyColorsArray( colors ) { - - const array = this.array; - let offset = 0; - - for ( let i = 0, l = colors.length; i < l; i ++ ) { - - let color = colors[ i ]; - - if ( color === undefined ) { - - console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); - color = new Color(); - - } - - array[ offset ++ ] = color.r; - array[ offset ++ ] = color.g; - array[ offset ++ ] = color.b; - - } - - return this; - - } - - copyVector2sArray( vectors ) { - - const array = this.array; - let offset = 0; - - for ( let i = 0, l = vectors.length; i < l; i ++ ) { - - let vector = vectors[ i ]; - - if ( vector === undefined ) { - - console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); - vector = new Vector2(); - - } - - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - - } - - return this; - - } - - copyVector3sArray( vectors ) { - - const array = this.array; - let offset = 0; - - for ( let i = 0, l = vectors.length; i < l; i ++ ) { - - let vector = vectors[ i ]; - - if ( vector === undefined ) { - - console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); - vector = new Vector3(); - - } - - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - array[ offset ++ ] = vector.z; - - } - - return this; - - } - - copyVector4sArray( vectors ) { - - const array = this.array; - let offset = 0; - - for ( let i = 0, l = vectors.length; i < l; i ++ ) { - - let vector = vectors[ i ]; - - if ( vector === undefined ) { - - console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); - vector = new Vector4(); - - } - - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - array[ offset ++ ] = vector.z; - array[ offset ++ ] = vector.w; - - } - - return this; - - } - - applyMatrix3( m ) { - - if ( this.itemSize === 2 ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector2$1.fromBufferAttribute( this, i ); - _vector2$1.applyMatrix3( m ); - - this.setXY( i, _vector2$1.x, _vector2$1.y ); - - } - - } else if ( this.itemSize === 3 ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.fromBufferAttribute( this, i ); - _vector$9.applyMatrix3( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - } - - return this; - - } - - applyMatrix4( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.x = this.getX( i ); - _vector$9.y = this.getY( i ); - _vector$9.z = this.getZ( i ); - - _vector$9.applyMatrix4( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - applyNormalMatrix( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.x = this.getX( i ); - _vector$9.y = this.getY( i ); - _vector$9.z = this.getZ( i ); - - _vector$9.applyNormalMatrix( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - transformDirection( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$9.x = this.getX( i ); - _vector$9.y = this.getY( i ); - _vector$9.z = this.getZ( i ); - - _vector$9.transformDirection( m ); - - this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); - - } - - return this; - - } - - set( value, offset = 0 ) { - - this.array.set( value, offset ); - - return this; - - } - - getX( index ) { - - return this.array[ index * this.itemSize ]; - - } - - setX( index, x ) { - - this.array[ index * this.itemSize ] = x; - - return this; - - } - - getY( index ) { - - return this.array[ index * this.itemSize + 1 ]; - - } - - setY( index, y ) { - - this.array[ index * this.itemSize + 1 ] = y; - - return this; - - } - - getZ( index ) { - - return this.array[ index * this.itemSize + 2 ]; - - } - - setZ( index, z ) { - - this.array[ index * this.itemSize + 2 ] = z; - - return this; - - } - - getW( index ) { - - return this.array[ index * this.itemSize + 3 ]; - - } - - setW( index, w ) { - - this.array[ index * this.itemSize + 3 ] = w; - - return this; - - } - - setXY( index, x, y ) { - - index *= this.itemSize; - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - - return this; - - } - - setXYZ( index, x, y, z ) { - - index *= this.itemSize; - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - - return this; - - } - - setXYZW( index, x, y, z, w ) { - - index *= this.itemSize; - - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; - this.array[ index + 3 ] = w; - - return this; - - } - - onUpload( callback ) { - - this.onUploadCallback = callback; - - return this; - - } - - clone() { - - return new this.constructor( this.array, this.itemSize ).copy( this ); - - } - - toJSON() { - - const data = { - itemSize: this.itemSize, - type: this.array.constructor.name, - array: Array.prototype.slice.call( this.array ), - normalized: this.normalized - }; - - if ( this.name !== '' ) data.name = this.name; - if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; - if ( this.updateRange.offset !== 0 || this.updateRange.count !== - 1 ) data.updateRange = this.updateRange; - - return data; - - } - - } - - BufferAttribute.prototype.isBufferAttribute = true; - - // - - class Int8BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int8Array( array ), itemSize, normalized ); - - } - - } - - class Uint8BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint8Array( array ), itemSize, normalized ); - - } - - } - - class Uint8ClampedBufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint8ClampedArray( array ), itemSize, normalized ); - - } - - } - - class Int16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int16Array( array ), itemSize, normalized ); - - } - - } - - class Uint16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint16Array( array ), itemSize, normalized ); - - } - - } - - class Int32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Int32Array( array ), itemSize, normalized ); - - } - - } - - class Uint32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint32Array( array ), itemSize, normalized ); - - } - - } - - class Float16BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Uint16Array( array ), itemSize, normalized ); - - } - - } - - Float16BufferAttribute.prototype.isFloat16BufferAttribute = true; - - class Float32BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Float32Array( array ), itemSize, normalized ); - - } - - } - - class Float64BufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized ) { - - super( new Float64Array( array ), itemSize, normalized ); - - } - - } - - function arrayMax( array ) { - - if ( array.length === 0 ) return - Infinity; - - let max = array[ 0 ]; - - for ( let i = 1, l = array.length; i < l; ++ i ) { - - if ( array[ i ] > max ) max = array[ i ]; - - } - - return max; - - } - - const TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - Uint8ClampedArray: Uint8ClampedArray, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array - }; - - function getTypedArray( type, buffer ) { - - return new TYPED_ARRAYS[ type ]( buffer ); - - } - - let _id = 0; - - const _m1 = /*@__PURE__*/ new Matrix4(); - const _obj = /*@__PURE__*/ new Object3D(); - const _offset = /*@__PURE__*/ new Vector3(); - const _box$1 = /*@__PURE__*/ new Box3(); - const _boxMorphTargets = /*@__PURE__*/ new Box3(); - const _vector$8 = /*@__PURE__*/ new Vector3(); - - class BufferGeometry extends EventDispatcher { - - constructor() { - - super(); - - Object.defineProperty( this, 'id', { value: _id ++ } ); - - this.uuid = generateUUID(); - - this.name = ''; - this.type = 'BufferGeometry'; - - this.index = null; - this.attributes = {}; - - this.morphAttributes = {}; - this.morphTargetsRelative = false; - - this.groups = []; - - this.boundingBox = null; - this.boundingSphere = null; - - this.drawRange = { start: 0, count: Infinity }; - - this.userData = {}; - - } - - getIndex() { - - return this.index; - - } - - setIndex( index ) { - - if ( Array.isArray( index ) ) { - - this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); - - } else { - - this.index = index; - - } - - return this; - - } - - getAttribute( name ) { - - return this.attributes[ name ]; - - } - - setAttribute( name, attribute ) { - - this.attributes[ name ] = attribute; - - return this; - - } - - deleteAttribute( name ) { - - delete this.attributes[ name ]; - - return this; - - } - - hasAttribute( name ) { - - return this.attributes[ name ] !== undefined; - - } - - addGroup( start, count, materialIndex = 0 ) { - - this.groups.push( { - - start: start, - count: count, - materialIndex: materialIndex - - } ); - - } - - clearGroups() { - - this.groups = []; - - } - - setDrawRange( start, count ) { - - this.drawRange.start = start; - this.drawRange.count = count; - - } - - applyMatrix4( matrix ) { - - const position = this.attributes.position; - - if ( position !== undefined ) { - - position.applyMatrix4( matrix ); - - position.needsUpdate = true; - - } - - const normal = this.attributes.normal; - - if ( normal !== undefined ) { - - const normalMatrix = new Matrix3().getNormalMatrix( matrix ); - - normal.applyNormalMatrix( normalMatrix ); - - normal.needsUpdate = true; - - } - - const tangent = this.attributes.tangent; - - if ( tangent !== undefined ) { - - tangent.transformDirection( matrix ); - - tangent.needsUpdate = true; - - } - - if ( this.boundingBox !== null ) { - - this.computeBoundingBox(); - - } - - if ( this.boundingSphere !== null ) { - - this.computeBoundingSphere(); - - } - - return this; - - } - - applyQuaternion( q ) { - - _m1.makeRotationFromQuaternion( q ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateX( angle ) { - - // rotate geometry around world x-axis - - _m1.makeRotationX( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateY( angle ) { - - // rotate geometry around world y-axis - - _m1.makeRotationY( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - rotateZ( angle ) { - - // rotate geometry around world z-axis - - _m1.makeRotationZ( angle ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - translate( x, y, z ) { - - // translate geometry - - _m1.makeTranslation( x, y, z ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - scale( x, y, z ) { - - // scale geometry - - _m1.makeScale( x, y, z ); - - this.applyMatrix4( _m1 ); - - return this; - - } - - lookAt( vector ) { - - _obj.lookAt( vector ); - - _obj.updateMatrix(); - - this.applyMatrix4( _obj.matrix ); - - return this; - - } - - center() { - - this.computeBoundingBox(); - - this.boundingBox.getCenter( _offset ).negate(); - - this.translate( _offset.x, _offset.y, _offset.z ); - - return this; - - } - - setFromPoints( points ) { - - const position = []; - - for ( let i = 0, l = points.length; i < l; i ++ ) { - - const point = points[ i ]; - position.push( point.x, point.y, point.z || 0 ); - - } - - this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); - - return this; - - } - - computeBoundingBox() { - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - const position = this.attributes.position; - const morphAttributesPosition = this.morphAttributes.position; - - if ( position && position.isGLBufferAttribute ) { - - console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this ); - - this.boundingBox.set( - new Vector3( - Infinity, - Infinity, - Infinity ), - new Vector3( + Infinity, + Infinity, + Infinity ) - ); - - return; - - } - - if ( position !== undefined ) { - - this.boundingBox.setFromBufferAttribute( position ); - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - _box$1.setFromBufferAttribute( morphAttribute ); - - if ( this.morphTargetsRelative ) { - - _vector$8.addVectors( this.boundingBox.min, _box$1.min ); - this.boundingBox.expandByPoint( _vector$8 ); - - _vector$8.addVectors( this.boundingBox.max, _box$1.max ); - this.boundingBox.expandByPoint( _vector$8 ); - - } else { - - this.boundingBox.expandByPoint( _box$1.min ); - this.boundingBox.expandByPoint( _box$1.max ); - - } - - } - - } - - } else { - - this.boundingBox.makeEmpty(); - - } - - if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { - - console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); - - } - - } - - computeBoundingSphere() { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - const position = this.attributes.position; - const morphAttributesPosition = this.morphAttributes.position; - - if ( position && position.isGLBufferAttribute ) { - - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this ); - - this.boundingSphere.set( new Vector3(), Infinity ); - - return; - - } - - if ( position ) { - - // first, find the center of the bounding sphere - - const center = this.boundingSphere.center; - - _box$1.setFromBufferAttribute( position ); - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - _boxMorphTargets.setFromBufferAttribute( morphAttribute ); - - if ( this.morphTargetsRelative ) { - - _vector$8.addVectors( _box$1.min, _boxMorphTargets.min ); - _box$1.expandByPoint( _vector$8 ); - - _vector$8.addVectors( _box$1.max, _boxMorphTargets.max ); - _box$1.expandByPoint( _vector$8 ); - - } else { - - _box$1.expandByPoint( _boxMorphTargets.min ); - _box$1.expandByPoint( _boxMorphTargets.max ); - - } - - } - - } - - _box$1.getCenter( center ); - - // second, try to find a boundingSphere with a radius smaller than the - // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - - let maxRadiusSq = 0; - - for ( let i = 0, il = position.count; i < il; i ++ ) { - - _vector$8.fromBufferAttribute( position, i ); - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); - - } - - // process morph attributes if present - - if ( morphAttributesPosition ) { - - for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - - const morphAttribute = morphAttributesPosition[ i ]; - const morphTargetsRelative = this.morphTargetsRelative; - - for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { - - _vector$8.fromBufferAttribute( morphAttribute, j ); - - if ( morphTargetsRelative ) { - - _offset.fromBufferAttribute( position, j ); - _vector$8.add( _offset ); - - } - - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); - - } - - } - - } - - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - - if ( isNaN( this.boundingSphere.radius ) ) { - - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); - - } - - } - - } - - computeTangents() { - - const index = this.index; - const attributes = this.attributes; - - // based on http://www.terathon.com/code/tangent.html - // (per vertex tangents) - - if ( index === null || - attributes.position === undefined || - attributes.normal === undefined || - attributes.uv === undefined ) { - - console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); - return; - - } - - const indices = index.array; - const positions = attributes.position.array; - const normals = attributes.normal.array; - const uvs = attributes.uv.array; - - const nVertices = positions.length / 3; - - if ( attributes.tangent === undefined ) { - - this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); - - } - - const tangents = attributes.tangent.array; - - const tan1 = [], tan2 = []; - - for ( let i = 0; i < nVertices; i ++ ) { - - tan1[ i ] = new Vector3(); - tan2[ i ] = new Vector3(); - - } - - const vA = new Vector3(), - vB = new Vector3(), - vC = new Vector3(), - - uvA = new Vector2(), - uvB = new Vector2(), - uvC = new Vector2(), - - sdir = new Vector3(), - tdir = new Vector3(); - - function handleTriangle( a, b, c ) { - - vA.fromArray( positions, a * 3 ); - vB.fromArray( positions, b * 3 ); - vC.fromArray( positions, c * 3 ); - - uvA.fromArray( uvs, a * 2 ); - uvB.fromArray( uvs, b * 2 ); - uvC.fromArray( uvs, c * 2 ); - - vB.sub( vA ); - vC.sub( vA ); - - uvB.sub( uvA ); - uvC.sub( uvA ); - - const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); - - // silently ignore degenerate uv triangles having coincident or colinear vertices - - if ( ! isFinite( r ) ) return; - - sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); - tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); - - tan1[ a ].add( sdir ); - tan1[ b ].add( sdir ); - tan1[ c ].add( sdir ); - - tan2[ a ].add( tdir ); - tan2[ b ].add( tdir ); - tan2[ c ].add( tdir ); - - } - - let groups = this.groups; - - if ( groups.length === 0 ) { - - groups = [ { - start: 0, - count: indices.length - } ]; - - } - - for ( let i = 0, il = groups.length; i < il; ++ i ) { - - const group = groups[ i ]; - - const start = group.start; - const count = group.count; - - for ( let j = start, jl = start + count; j < jl; j += 3 ) { - - handleTriangle( - indices[ j + 0 ], - indices[ j + 1 ], - indices[ j + 2 ] - ); - - } - - } - - const tmp = new Vector3(), tmp2 = new Vector3(); - const n = new Vector3(), n2 = new Vector3(); - - function handleVertex( v ) { - - n.fromArray( normals, v * 3 ); - n2.copy( n ); - - const t = tan1[ v ]; - - // Gram-Schmidt orthogonalize - - tmp.copy( t ); - tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); - - // Calculate handedness - - tmp2.crossVectors( n2, t ); - const test = tmp2.dot( tan2[ v ] ); - const w = ( test < 0.0 ) ? - 1.0 : 1.0; - - tangents[ v * 4 ] = tmp.x; - tangents[ v * 4 + 1 ] = tmp.y; - tangents[ v * 4 + 2 ] = tmp.z; - tangents[ v * 4 + 3 ] = w; - - } - - for ( let i = 0, il = groups.length; i < il; ++ i ) { - - const group = groups[ i ]; - - const start = group.start; - const count = group.count; - - for ( let j = start, jl = start + count; j < jl; j += 3 ) { - - handleVertex( indices[ j + 0 ] ); - handleVertex( indices[ j + 1 ] ); - handleVertex( indices[ j + 2 ] ); - - } - - } - - } - - computeVertexNormals() { - - const index = this.index; - const positionAttribute = this.getAttribute( 'position' ); - - if ( positionAttribute !== undefined ) { - - let normalAttribute = this.getAttribute( 'normal' ); - - if ( normalAttribute === undefined ) { - - normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); - this.setAttribute( 'normal', normalAttribute ); - - } else { - - // reset existing normals to zero - - for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { - - normalAttribute.setXYZ( i, 0, 0, 0 ); - - } - - } - - const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); - const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); - const cb = new Vector3(), ab = new Vector3(); - - // indexed elements - - if ( index ) { - - for ( let i = 0, il = index.count; i < il; i += 3 ) { - - const vA = index.getX( i + 0 ); - const vB = index.getX( i + 1 ); - const vC = index.getX( i + 2 ); - - pA.fromBufferAttribute( positionAttribute, vA ); - pB.fromBufferAttribute( positionAttribute, vB ); - pC.fromBufferAttribute( positionAttribute, vC ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - nA.fromBufferAttribute( normalAttribute, vA ); - nB.fromBufferAttribute( normalAttribute, vB ); - nC.fromBufferAttribute( normalAttribute, vC ); - - nA.add( cb ); - nB.add( cb ); - nC.add( cb ); - - normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); - normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); - normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); - - } - - } else { - - // non-indexed elements (unconnected triangle soup) - - for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { - - pA.fromBufferAttribute( positionAttribute, i + 0 ); - pB.fromBufferAttribute( positionAttribute, i + 1 ); - pC.fromBufferAttribute( positionAttribute, i + 2 ); - - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); - - normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); - normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); - normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); - - } - - } - - this.normalizeNormals(); - - normalAttribute.needsUpdate = true; - - } - - } - - merge( geometry, offset ) { - - if ( ! ( geometry && geometry.isBufferGeometry ) ) { - - console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); - return; - - } - - if ( offset === undefined ) { - - offset = 0; - - console.warn( - 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. ' - + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.' - ); - - } - - const attributes = this.attributes; - - for ( const key in attributes ) { - - if ( geometry.attributes[ key ] === undefined ) continue; - - const attribute1 = attributes[ key ]; - const attributeArray1 = attribute1.array; - - const attribute2 = geometry.attributes[ key ]; - const attributeArray2 = attribute2.array; - - const attributeOffset = attribute2.itemSize * offset; - const length = Math.min( attributeArray2.length, attributeArray1.length - attributeOffset ); - - for ( let i = 0, j = attributeOffset; i < length; i ++, j ++ ) { - - attributeArray1[ j ] = attributeArray2[ i ]; - - } - - } - - return this; - - } - - normalizeNormals() { - - const normals = this.attributes.normal; - - for ( let i = 0, il = normals.count; i < il; i ++ ) { - - _vector$8.fromBufferAttribute( normals, i ); - - _vector$8.normalize(); - - normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); - - } - - } - - toNonIndexed() { - - function convertBufferAttribute( attribute, indices ) { - - const array = attribute.array; - const itemSize = attribute.itemSize; - const normalized = attribute.normalized; - - const array2 = new array.constructor( indices.length * itemSize ); - - let index = 0, index2 = 0; - - for ( let i = 0, l = indices.length; i < l; i ++ ) { - - if ( attribute.isInterleavedBufferAttribute ) { - - index = indices[ i ] * attribute.data.stride + attribute.offset; - - } else { - - index = indices[ i ] * itemSize; - - } - - for ( let j = 0; j < itemSize; j ++ ) { - - array2[ index2 ++ ] = array[ index ++ ]; - - } - - } - - return new BufferAttribute( array2, itemSize, normalized ); - - } - - // - - if ( this.index === null ) { - - console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); - return this; - - } - - const geometry2 = new BufferGeometry(); - - const indices = this.index.array; - const attributes = this.attributes; - - // attributes - - for ( const name in attributes ) { - - const attribute = attributes[ name ]; - - const newAttribute = convertBufferAttribute( attribute, indices ); - - geometry2.setAttribute( name, newAttribute ); - - } - - // morph attributes - - const morphAttributes = this.morphAttributes; - - for ( const name in morphAttributes ) { - - const morphArray = []; - const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - - for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { - - const attribute = morphAttribute[ i ]; - - const newAttribute = convertBufferAttribute( attribute, indices ); - - morphArray.push( newAttribute ); - - } - - geometry2.morphAttributes[ name ] = morphArray; - - } - - geometry2.morphTargetsRelative = this.morphTargetsRelative; - - // groups - - const groups = this.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - geometry2.addGroup( group.start, group.count, group.materialIndex ); - - } - - return geometry2; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.5, - type: 'BufferGeometry', - generator: 'BufferGeometry.toJSON' - } - }; - - // standard BufferGeometry serialization - - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; - if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; - - if ( this.parameters !== undefined ) { - - const parameters = this.parameters; - - for ( const key in parameters ) { - - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; - - } - - return data; - - } - - // for simplicity the code assumes attributes are not shared across geometries, see #15811 - - data.data = { attributes: {} }; - - const index = this.index; - - if ( index !== null ) { - - data.data.index = { - type: index.array.constructor.name, - array: Array.prototype.slice.call( index.array ) - }; - - } - - const attributes = this.attributes; - - for ( const key in attributes ) { - - const attribute = attributes[ key ]; - - data.data.attributes[ key ] = attribute.toJSON( data.data ); - - } - - const morphAttributes = {}; - let hasMorphAttributes = false; - - for ( const key in this.morphAttributes ) { - - const attributeArray = this.morphAttributes[ key ]; - - const array = []; - - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - - const attribute = attributeArray[ i ]; - - array.push( attribute.toJSON( data.data ) ); - - } - - if ( array.length > 0 ) { - - morphAttributes[ key ] = array; - - hasMorphAttributes = true; - - } - - } - - if ( hasMorphAttributes ) { - - data.data.morphAttributes = morphAttributes; - data.data.morphTargetsRelative = this.morphTargetsRelative; - - } - - const groups = this.groups; - - if ( groups.length > 0 ) { - - data.data.groups = JSON.parse( JSON.stringify( groups ) ); - - } - - const boundingSphere = this.boundingSphere; - - if ( boundingSphere !== null ) { - - data.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - }; - - } - - return data; - - } - - clone() { - - /* - // Handle primitives - - const parameters = this.parameters; - - if ( parameters !== undefined ) { - - const values = []; - - for ( const key in parameters ) { - - values.push( parameters[ key ] ); - - } - - const geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; - - } - - return new this.constructor().copy( this ); - */ - - return new BufferGeometry().copy( this ); - - } - - copy( source ) { - - // reset - - this.index = null; - this.attributes = {}; - this.morphAttributes = {}; - this.groups = []; - this.boundingBox = null; - this.boundingSphere = null; - - // used for storing cloned, shared data - - const data = {}; - - // name - - this.name = source.name; - - // index - - const index = source.index; - - if ( index !== null ) { - - this.setIndex( index.clone( data ) ); - - } - - // attributes - - const attributes = source.attributes; - - for ( const name in attributes ) { - - const attribute = attributes[ name ]; - this.setAttribute( name, attribute.clone( data ) ); - - } - - // morph attributes - - const morphAttributes = source.morphAttributes; - - for ( const name in morphAttributes ) { - - const array = []; - const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes - - for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { - - array.push( morphAttribute[ i ].clone( data ) ); - - } - - this.morphAttributes[ name ] = array; - - } - - this.morphTargetsRelative = source.morphTargetsRelative; - - // groups - - const groups = source.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); - - } - - // bounding box - - const boundingBox = source.boundingBox; - - if ( boundingBox !== null ) { - - this.boundingBox = boundingBox.clone(); - - } - - // bounding sphere - - const boundingSphere = source.boundingSphere; - - if ( boundingSphere !== null ) { - - this.boundingSphere = boundingSphere.clone(); - - } - - // draw range - - this.drawRange.start = source.drawRange.start; - this.drawRange.count = source.drawRange.count; - - // user data - - this.userData = source.userData; - - return this; - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - } - - BufferGeometry.prototype.isBufferGeometry = true; - - const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); - const _ray$2 = /*@__PURE__*/ new Ray(); - const _sphere$3 = /*@__PURE__*/ new Sphere(); - - const _vA$1 = /*@__PURE__*/ new Vector3(); - const _vB$1 = /*@__PURE__*/ new Vector3(); - const _vC$1 = /*@__PURE__*/ new Vector3(); - - const _tempA = /*@__PURE__*/ new Vector3(); - const _tempB = /*@__PURE__*/ new Vector3(); - const _tempC = /*@__PURE__*/ new Vector3(); - - const _morphA = /*@__PURE__*/ new Vector3(); - const _morphB = /*@__PURE__*/ new Vector3(); - const _morphC = /*@__PURE__*/ new Vector3(); - - const _uvA$1 = /*@__PURE__*/ new Vector2(); - const _uvB$1 = /*@__PURE__*/ new Vector2(); - const _uvC$1 = /*@__PURE__*/ new Vector2(); - - const _intersectionPoint = /*@__PURE__*/ new Vector3(); - const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); - - class Mesh extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { - - super(); - - this.type = 'Mesh'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source ) { - - super.copy( source ); - - if ( source.morphTargetInfluences !== undefined ) { - - this.morphTargetInfluences = source.morphTargetInfluences.slice(); - - } - - if ( source.morphTargetDictionary !== undefined ) { - - this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); - - } - - this.material = source.material; - this.geometry = source.geometry; - - return this; - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - if ( geometry.isBufferGeometry ) { - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } else { - - const morphTargets = geometry.morphTargets; - - if ( morphTargets !== undefined && morphTargets.length > 0 ) { - - console.error( 'THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - - } - - } - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const material = this.material; - const matrixWorld = this.matrixWorld; - - if ( material === undefined ) return; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$3.copy( geometry.boundingSphere ); - _sphere$3.applyMatrix4( matrixWorld ); - - if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; - - // - - _inverseMatrix$2.copy( matrixWorld ).invert(); - _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); - - // Check boundingBox before continuing - - if ( geometry.boundingBox !== null ) { - - if ( _ray$2.intersectsBox( geometry.boundingBox ) === false ) return; - - } - - let intersection; - - if ( geometry.isBufferGeometry ) { - - const index = geometry.index; - const position = geometry.attributes.position; - const morphPosition = geometry.morphAttributes.position; - const morphTargetsRelative = geometry.morphTargetsRelative; - const uv = geometry.attributes.uv; - const uv2 = geometry.attributes.uv2; - const groups = geometry.groups; - const drawRange = geometry.drawRange; - - if ( index !== null ) { - - // indexed buffer geometry - - if ( Array.isArray( material ) ) { - - for ( let i = 0, il = groups.length; i < il; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - const start = Math.max( group.start, drawRange.start ); - const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); - - for ( let j = start, jl = end; j < jl; j += 3 ) { - - const a = index.getX( j ); - const b = index.getX( j + 1 ); - const c = index.getX( j + 2 ); - - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics - intersection.face.materialIndex = group.materialIndex; - intersects.push( intersection ); - - } - - } - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i += 3 ) { - - const a = index.getX( i ); - const b = index.getX( i + 1 ); - const c = index.getX( i + 2 ); - - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics - intersects.push( intersection ); - - } - - } - - } - - } else if ( position !== undefined ) { - - // non-indexed buffer geometry - - if ( Array.isArray( material ) ) { - - for ( let i = 0, il = groups.length; i < il; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - const start = Math.max( group.start, drawRange.start ); - const end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); - - for ( let j = start, jl = end; j < jl; j += 3 ) { - - const a = j; - const b = j + 1; - const c = j + 2; - - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics - intersection.face.materialIndex = group.materialIndex; - intersects.push( intersection ); - - } - - } - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i += 3 ) { - - const a = i; - const b = i + 1; - const c = i + 2; - - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - - if ( intersection ) { - - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics - intersects.push( intersection ); - - } - - } - - } - - } - - } else if ( geometry.isGeometry ) { - - console.error( 'THREE.Mesh.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - - } - - } - - } - - Mesh.prototype.isMesh = true; - - function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { - - let intersect; - - if ( material.side === BackSide ) { - - intersect = ray.intersectTriangle( pC, pB, pA, true, point ); - - } else { - - intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); - - } - - if ( intersect === null ) return null; - - _intersectionPointWorld.copy( point ); - _intersectionPointWorld.applyMatrix4( object.matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); - - if ( distance < raycaster.near || distance > raycaster.far ) return null; - - return { - distance: distance, - point: _intersectionPointWorld.clone(), - object: object - }; - - } - - function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) { - - _vA$1.fromBufferAttribute( position, a ); - _vB$1.fromBufferAttribute( position, b ); - _vC$1.fromBufferAttribute( position, c ); - - const morphInfluences = object.morphTargetInfluences; - - if ( morphPosition && morphInfluences ) { - - _morphA.set( 0, 0, 0 ); - _morphB.set( 0, 0, 0 ); - _morphC.set( 0, 0, 0 ); - - for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { - - const influence = morphInfluences[ i ]; - const morphAttribute = morphPosition[ i ]; - - if ( influence === 0 ) continue; - - _tempA.fromBufferAttribute( morphAttribute, a ); - _tempB.fromBufferAttribute( morphAttribute, b ); - _tempC.fromBufferAttribute( morphAttribute, c ); - - if ( morphTargetsRelative ) { - - _morphA.addScaledVector( _tempA, influence ); - _morphB.addScaledVector( _tempB, influence ); - _morphC.addScaledVector( _tempC, influence ); - - } else { - - _morphA.addScaledVector( _tempA.sub( _vA$1 ), influence ); - _morphB.addScaledVector( _tempB.sub( _vB$1 ), influence ); - _morphC.addScaledVector( _tempC.sub( _vC$1 ), influence ); - - } - - } - - _vA$1.add( _morphA ); - _vB$1.add( _morphB ); - _vC$1.add( _morphC ); - - } - - if ( object.isSkinnedMesh ) { - - object.boneTransform( a, _vA$1 ); - object.boneTransform( b, _vB$1 ); - object.boneTransform( c, _vC$1 ); - - } - - const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); - - if ( intersection ) { - - if ( uv ) { - - _uvA$1.fromBufferAttribute( uv, a ); - _uvB$1.fromBufferAttribute( uv, b ); - _uvC$1.fromBufferAttribute( uv, c ); - - intersection.uv = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); - - } - - if ( uv2 ) { - - _uvA$1.fromBufferAttribute( uv2, a ); - _uvB$1.fromBufferAttribute( uv2, b ); - _uvC$1.fromBufferAttribute( uv2, c ); - - intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); - - } - - const face = { - a: a, - b: b, - c: c, - normal: new Vector3(), - materialIndex: 0 - }; - - Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); - - intersection.face = face; - - } - - return intersection; - - } - - class BoxGeometry extends BufferGeometry { - - constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) { - - super(); - - this.type = 'BoxGeometry'; - - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; - - const scope = this; - - // segments - - widthSegments = Math.floor( widthSegments ); - heightSegments = Math.floor( heightSegments ); - depthSegments = Math.floor( depthSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let numberOfVertices = 0; - let groupStart = 0; - - // build each side of the box geometry - - buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px - buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx - buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py - buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny - buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz - buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { - - const segmentWidth = width / gridX; - const segmentHeight = height / gridY; - - const widthHalf = width / 2; - const heightHalf = height / 2; - const depthHalf = depth / 2; - - const gridX1 = gridX + 1; - const gridY1 = gridY + 1; - - let vertexCounter = 0; - let groupCount = 0; - - const vector = new Vector3(); - - // generate vertices, normals and uvs - - for ( let iy = 0; iy < gridY1; iy ++ ) { - - const y = iy * segmentHeight - heightHalf; - - for ( let ix = 0; ix < gridX1; ix ++ ) { - - const x = ix * segmentWidth - widthHalf; - - // set values to correct vector component - - vector[ u ] = x * udir; - vector[ v ] = y * vdir; - vector[ w ] = depthHalf; - - // now apply vector to vertex buffer - - vertices.push( vector.x, vector.y, vector.z ); - - // set values to correct vector component - - vector[ u ] = 0; - vector[ v ] = 0; - vector[ w ] = depth > 0 ? 1 : - 1; - - // now apply vector to normal buffer - - normals.push( vector.x, vector.y, vector.z ); - - // uvs - - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); - - // counters - - vertexCounter += 1; - - } - - } - - // indices - - // 1. you need three indices to draw a single face - // 2. a single segment consists of two faces - // 3. so we need to generate six (2*3) indices per segment - - for ( let iy = 0; iy < gridY; iy ++ ) { - - for ( let ix = 0; ix < gridX; ix ++ ) { - - const a = numberOfVertices + ix + gridX1 * iy; - const b = numberOfVertices + ix + gridX1 * ( iy + 1 ); - const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); - const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - // increase counter - - groupCount += 6; - - } - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, materialIndex ); - - // calculate new start value for groups - - groupStart += groupCount; - - // update total number of vertices - - numberOfVertices += vertexCounter; - - } - - } - - static fromJSON( data ) { - - return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); - - } - - } - - /** - * Uniform Utilities - */ - - function cloneUniforms( src ) { - - const dst = {}; - - for ( const u in src ) { - - dst[ u ] = {}; - - for ( const p in src[ u ] ) { - - const property = src[ u ][ p ]; - - if ( property && ( property.isColor || - property.isMatrix3 || property.isMatrix4 || - property.isVector2 || property.isVector3 || property.isVector4 || - property.isTexture || property.isQuaternion ) ) { - - dst[ u ][ p ] = property.clone(); - - } else if ( Array.isArray( property ) ) { - - dst[ u ][ p ] = property.slice(); - - } else { - - dst[ u ][ p ] = property; - - } - - } - - } - - return dst; - - } - - function mergeUniforms( uniforms ) { - - const merged = {}; - - for ( let u = 0; u < uniforms.length; u ++ ) { - - const tmp = cloneUniforms( uniforms[ u ] ); - - for ( const p in tmp ) { - - merged[ p ] = tmp[ p ]; - - } - - } - - return merged; - - } - - // Legacy - - const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; - - var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; - - var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; - - /** - * parameters = { - * defines: { "label" : "value" }, - * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } }, - * - * fragmentShader: , - * vertexShader: , - * - * wireframe: , - * wireframeLinewidth: , - * - * lights: - * } - */ - - class ShaderMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'ShaderMaterial'; - - this.defines = {}; - this.uniforms = {}; - - this.vertexShader = default_vertex; - this.fragmentShader = default_fragment; - - this.linewidth = 1; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; // set to use scene fog - this.lights = false; // set to use scene lights - this.clipping = false; // set to use user-defined clipping planes - - this.extensions = { - derivatives: false, // set to use derivatives - fragDepth: false, // set to use fragment depth values - drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false // set to use shader texture LOD - }; - - // When rendered geometry doesn't include these attributes but the material does, - // use these default values in WebGL. This avoids errors when buffer data is missing. - this.defaultAttributeValues = { - 'color': [ 1, 1, 1 ], - 'uv': [ 0, 0 ], - 'uv2': [ 0, 0 ] - }; - - this.index0AttributeName = undefined; - this.uniformsNeedUpdate = false; - - this.glslVersion = null; - - if ( parameters !== undefined ) { - - if ( parameters.attributes !== undefined ) { - - console.error( 'THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.' ); - - } - - this.setValues( parameters ); - - } - - } - - copy( source ) { - - super.copy( source ); - - this.fragmentShader = source.fragmentShader; - this.vertexShader = source.vertexShader; - - this.uniforms = cloneUniforms( source.uniforms ); - - this.defines = Object.assign( {}, source.defines ); - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - this.lights = source.lights; - this.clipping = source.clipping; - - this.extensions = Object.assign( {}, source.extensions ); - - this.glslVersion = source.glslVersion; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.glslVersion = this.glslVersion; - data.uniforms = {}; - - for ( const name in this.uniforms ) { - - const uniform = this.uniforms[ name ]; - const value = uniform.value; - - if ( value && value.isTexture ) { - - data.uniforms[ name ] = { - type: 't', - value: value.toJSON( meta ).uuid - }; - - } else if ( value && value.isColor ) { - - data.uniforms[ name ] = { - type: 'c', - value: value.getHex() - }; - - } else if ( value && value.isVector2 ) { - - data.uniforms[ name ] = { - type: 'v2', - value: value.toArray() - }; - - } else if ( value && value.isVector3 ) { - - data.uniforms[ name ] = { - type: 'v3', - value: value.toArray() - }; - - } else if ( value && value.isVector4 ) { - - data.uniforms[ name ] = { - type: 'v4', - value: value.toArray() - }; - - } else if ( value && value.isMatrix3 ) { - - data.uniforms[ name ] = { - type: 'm3', - value: value.toArray() - }; - - } else if ( value && value.isMatrix4 ) { - - data.uniforms[ name ] = { - type: 'm4', - value: value.toArray() - }; - - } else { - - data.uniforms[ name ] = { - value: value - }; - - // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far - - } - - } - - if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; - - data.vertexShader = this.vertexShader; - data.fragmentShader = this.fragmentShader; - - const extensions = {}; - - for ( const key in this.extensions ) { - - if ( this.extensions[ key ] === true ) extensions[ key ] = true; - - } - - if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; - - return data; - - } - - } - - ShaderMaterial.prototype.isShaderMaterial = true; - - class Camera extends Object3D { - - constructor() { - - super(); - - this.type = 'Camera'; - - this.matrixWorldInverse = new Matrix4(); - - this.projectionMatrix = new Matrix4(); - this.projectionMatrixInverse = new Matrix4(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.matrixWorldInverse.copy( source.matrixWorldInverse ); - - this.projectionMatrix.copy( source.projectionMatrix ); - this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); - - return this; - - } - - getWorldDirection( target ) { - - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; - - return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); - - } - - updateWorldMatrix( updateParents, updateChildren ) { - - super.updateWorldMatrix( updateParents, updateChildren ); - - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - } - - Camera.prototype.isCamera = true; - - class PerspectiveCamera extends Camera { - - constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) { - - super(); - - this.type = 'PerspectiveCamera'; - - this.fov = fov; - this.zoom = 1; - - this.near = near; - this.far = far; - this.focus = 10; - - this.aspect = aspect; - this.view = null; - - this.filmGauge = 35; // width of the film (default in millimeters) - this.filmOffset = 0; // horizontal film offset (same unit as gauge) - - this.updateProjectionMatrix(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.fov = source.fov; - this.zoom = source.zoom; - - this.near = source.near; - this.far = source.far; - this.focus = source.focus; - - this.aspect = source.aspect; - this.view = source.view === null ? null : Object.assign( {}, source.view ); - - this.filmGauge = source.filmGauge; - this.filmOffset = source.filmOffset; - - return this; - - } - - /** - * Sets the FOV by focal length in respect to the current .filmGauge. - * - * The default film gauge is 35, so that the focal length can be specified for - * a 35mm (full frame) camera. - * - * Values for focal length and film gauge must have the same unit. - */ - setFocalLength( focalLength ) { - - /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ - const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; - - this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope ); - this.updateProjectionMatrix(); - - } - - /** - * Calculates the focal length from the current .fov and .filmGauge. - */ - getFocalLength() { - - const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov ); - - return 0.5 * this.getFilmHeight() / vExtentSlope; - - } - - getEffectiveFOV() { - - return RAD2DEG * 2 * Math.atan( - Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom ); - - } - - getFilmWidth() { - - // film not completely covered in portrait format (aspect < 1) - return this.filmGauge * Math.min( this.aspect, 1 ); - - } - - getFilmHeight() { - - // film not completely covered in landscape format (aspect > 1) - return this.filmGauge / Math.max( this.aspect, 1 ); - - } - - /** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * const w = 1920; - * const h = 1080; - * const fullWidth = w * 3; - * const fullHeight = h * 2; - * - * --A-- - * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - - this.aspect = fullWidth / fullHeight; - - if ( this.view === null ) { - - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; - - } - - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; - - this.updateProjectionMatrix(); - - } - - clearViewOffset() { - - if ( this.view !== null ) { - - this.view.enabled = false; - - } - - this.updateProjectionMatrix(); - - } - - updateProjectionMatrix() { - - const near = this.near; - let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom; - let height = 2 * top; - let width = this.aspect * height; - let left = - 0.5 * width; - const view = this.view; - - if ( this.view !== null && this.view.enabled ) { - - const fullWidth = view.fullWidth, - fullHeight = view.fullHeight; - - left += view.offsetX * width / fullWidth; - top -= view.offsetY * height / fullHeight; - width *= view.width / fullWidth; - height *= view.height / fullHeight; - - } - - const skew = this.filmOffset; - if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); - - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.fov = this.fov; - data.object.zoom = this.zoom; - - data.object.near = this.near; - data.object.far = this.far; - data.object.focus = this.focus; - - data.object.aspect = this.aspect; - - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - - data.object.filmGauge = this.filmGauge; - data.object.filmOffset = this.filmOffset; - - return data; - - } - - } - - PerspectiveCamera.prototype.isPerspectiveCamera = true; - - const fov = 90, aspect = 1; - - class CubeCamera extends Object3D { - - constructor( near, far, renderTarget ) { - - super(); - - this.type = 'CubeCamera'; - - if ( renderTarget.isWebGLCubeRenderTarget !== true ) { - - console.error( 'THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.' ); - return; - - } - - this.renderTarget = renderTarget; - - const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); - cameraPX.layers = this.layers; - cameraPX.up.set( 0, - 1, 0 ); - cameraPX.lookAt( new Vector3( 1, 0, 0 ) ); - this.add( cameraPX ); - - const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); - cameraNX.layers = this.layers; - cameraNX.up.set( 0, - 1, 0 ); - cameraNX.lookAt( new Vector3( - 1, 0, 0 ) ); - this.add( cameraNX ); - - const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); - cameraPY.layers = this.layers; - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( new Vector3( 0, 1, 0 ) ); - this.add( cameraPY ); - - const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); - cameraNY.layers = this.layers; - cameraNY.up.set( 0, 0, - 1 ); - cameraNY.lookAt( new Vector3( 0, - 1, 0 ) ); - this.add( cameraNY ); - - const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.layers = this.layers; - cameraPZ.up.set( 0, - 1, 0 ); - cameraPZ.lookAt( new Vector3( 0, 0, 1 ) ); - this.add( cameraPZ ); - - const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.layers = this.layers; - cameraNZ.up.set( 0, - 1, 0 ); - cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) ); - this.add( cameraNZ ); - - } - - update( renderer, scene ) { - - if ( this.parent === null ) this.updateMatrixWorld(); - - const renderTarget = this.renderTarget; - - const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; - - const currentXrEnabled = renderer.xr.enabled; - const currentRenderTarget = renderer.getRenderTarget(); - - renderer.xr.enabled = false; - - const generateMipmaps = renderTarget.texture.generateMipmaps; - - renderTarget.texture.generateMipmaps = false; - - renderer.setRenderTarget( renderTarget, 0 ); - renderer.render( scene, cameraPX ); - - renderer.setRenderTarget( renderTarget, 1 ); - renderer.render( scene, cameraNX ); - - renderer.setRenderTarget( renderTarget, 2 ); - renderer.render( scene, cameraPY ); - - renderer.setRenderTarget( renderTarget, 3 ); - renderer.render( scene, cameraNY ); - - renderer.setRenderTarget( renderTarget, 4 ); - renderer.render( scene, cameraPZ ); - - renderTarget.texture.generateMipmaps = generateMipmaps; - - renderer.setRenderTarget( renderTarget, 5 ); - renderer.render( scene, cameraNZ ); - - renderer.setRenderTarget( currentRenderTarget ); - - renderer.xr.enabled = currentXrEnabled; - - } - - } - - class CubeTexture extends Texture { - - constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { - - images = images !== undefined ? images : []; - mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - format = format !== undefined ? format : RGBFormat; - - super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - - this.flipY = false; - - } - - get images() { - - return this.image; - - } - - set images( value ) { - - this.image = value; - - } - - } - - CubeTexture.prototype.isCubeTexture = true; - - class WebGLCubeRenderTarget extends WebGLRenderTarget { - - constructor( size, options, dummy ) { - - if ( Number.isInteger( options ) ) { - - console.warn( 'THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )' ); - - options = dummy; - - } - - super( size, size, options ); - - options = options || {}; - - // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) - // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, - // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. - - // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped - // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture - // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). - - this.texture = new CubeTexture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - this.texture.isRenderTargetTexture = true; - - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; - - this.texture._needsFlipEnvMap = false; - - } - - fromEquirectangularTexture( renderer, texture ) { - - this.texture.type = texture.type; - this.texture.format = RGBAFormat; // see #18859 - this.texture.encoding = texture.encoding; - - this.texture.generateMipmaps = texture.generateMipmaps; - this.texture.minFilter = texture.minFilter; - this.texture.magFilter = texture.magFilter; - - const shader = { - - uniforms: { - tEquirect: { value: null }, - }, - - vertexShader: /* glsl */` - - varying vec3 vWorldDirection; - - vec3 transformDirection( in vec3 dir, in mat4 matrix ) { - - return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); - - } - - void main() { - - vWorldDirection = transformDirection( position, modelMatrix ); - - #include - #include - - } - `, - - fragmentShader: /* glsl */` - - uniform sampler2D tEquirect; - - varying vec3 vWorldDirection; - - #include - - void main() { - - vec3 direction = normalize( vWorldDirection ); - - vec2 sampleUV = equirectUv( direction ); - - gl_FragColor = texture2D( tEquirect, sampleUV ); - - } - ` - }; - - const geometry = new BoxGeometry( 5, 5, 5 ); - - const material = new ShaderMaterial( { - - name: 'CubemapFromEquirect', - - uniforms: cloneUniforms( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader, - side: BackSide, - blending: NoBlending - - } ); - - material.uniforms.tEquirect.value = texture; - - const mesh = new Mesh( geometry, material ); - - const currentMinFilter = texture.minFilter; - - // Avoid blurred poles - if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter; - - const camera = new CubeCamera( 1, 10, this ); - camera.update( renderer, mesh ); - - texture.minFilter = currentMinFilter; - - mesh.geometry.dispose(); - mesh.material.dispose(); - - return this; - - } - - clear( renderer, color, depth, stencil ) { - - const currentRenderTarget = renderer.getRenderTarget(); - - for ( let i = 0; i < 6; i ++ ) { - - renderer.setRenderTarget( this, i ); - - renderer.clear( color, depth, stencil ); - - } - - renderer.setRenderTarget( currentRenderTarget ); - - } - - } - - WebGLCubeRenderTarget.prototype.isWebGLCubeRenderTarget = true; - - const _vector1 = /*@__PURE__*/ new Vector3(); - const _vector2 = /*@__PURE__*/ new Vector3(); - const _normalMatrix = /*@__PURE__*/ new Matrix3(); - - class Plane { - - constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { - - // normal is assumed to be normalized - - this.normal = normal; - this.constant = constant; - - } - - set( normal, constant ) { - - this.normal.copy( normal ); - this.constant = constant; - - return this; - - } - - setComponents( x, y, z, w ) { - - this.normal.set( x, y, z ); - this.constant = w; - - return this; - - } - - setFromNormalAndCoplanarPoint( normal, point ) { - - this.normal.copy( normal ); - this.constant = - point.dot( this.normal ); - - return this; - - } - - setFromCoplanarPoints( a, b, c ) { - - const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); - - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - - this.setFromNormalAndCoplanarPoint( normal, a ); - - return this; - - } - - copy( plane ) { - - this.normal.copy( plane.normal ); - this.constant = plane.constant; - - return this; - - } - - normalize() { - - // Note: will lead to a divide by zero if the plane is invalid. - - const inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar( inverseNormalLength ); - this.constant *= inverseNormalLength; - - return this; - - } - - negate() { - - this.constant *= - 1; - this.normal.negate(); - - return this; - - } - - distanceToPoint( point ) { - - return this.normal.dot( point ) + this.constant; - - } - - distanceToSphere( sphere ) { - - return this.distanceToPoint( sphere.center ) - sphere.radius; - - } - - projectPoint( point, target ) { - - return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); - - } - - intersectLine( line, target ) { - - const direction = line.delta( _vector1 ); - - const denominator = this.normal.dot( direction ); - - if ( denominator === 0 ) { - - // line is coplanar, return origin - if ( this.distanceToPoint( line.start ) === 0 ) { - - return target.copy( line.start ); - - } - - // Unsure if this is the correct method to handle this case. - return null; - - } - - const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - - if ( t < 0 || t > 1 ) { - - return null; - - } - - return target.copy( direction ).multiplyScalar( t ).add( line.start ); - - } - - intersectsLine( line ) { - - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - - const startSign = this.distanceToPoint( line.start ); - const endSign = this.distanceToPoint( line.end ); - - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - - } - - intersectsBox( box ) { - - return box.intersectsPlane( this ); - - } - - intersectsSphere( sphere ) { - - return sphere.intersectsPlane( this ); - - } - - coplanarPoint( target ) { - - return target.copy( this.normal ).multiplyScalar( - this.constant ); - - } - - applyMatrix4( matrix, optionalNormalMatrix ) { - - const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); - - const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); - - const normal = this.normal.applyMatrix3( normalMatrix ).normalize(); - - this.constant = - referencePoint.dot( normal ); - - return this; - - } - - translate( offset ) { - - this.constant -= offset.dot( this.normal ); - - return this; - - } - - equals( plane ) { - - return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - } - - Plane.prototype.isPlane = true; - - const _sphere$2 = /*@__PURE__*/ new Sphere(); - const _vector$7 = /*@__PURE__*/ new Vector3(); - - class Frustum { - - constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { - - this.planes = [ p0, p1, p2, p3, p4, p5 ]; - - } - - set( p0, p1, p2, p3, p4, p5 ) { - - const planes = this.planes; - - planes[ 0 ].copy( p0 ); - planes[ 1 ].copy( p1 ); - planes[ 2 ].copy( p2 ); - planes[ 3 ].copy( p3 ); - planes[ 4 ].copy( p4 ); - planes[ 5 ].copy( p5 ); - - return this; - - } - - copy( frustum ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - planes[ i ].copy( frustum.planes[ i ] ); - - } - - return this; - - } - - setFromProjectionMatrix( m ) { - - const planes = this.planes; - const me = m.elements; - const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; - const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; - const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; - const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; - - planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); - planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); - planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); - planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); - planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); - - return this; - - } - - intersectsObject( object ) { - - const geometry = object.geometry; - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$2.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); - - return this.intersectsSphere( _sphere$2 ); - - } - - intersectsSprite( sprite ) { - - _sphere$2.center.set( 0, 0, 0 ); - _sphere$2.radius = 0.7071067811865476; - _sphere$2.applyMatrix4( sprite.matrixWorld ); - - return this.intersectsSphere( _sphere$2 ); - - } - - intersectsSphere( sphere ) { - - const planes = this.planes; - const center = sphere.center; - const negRadius = - sphere.radius; - - for ( let i = 0; i < 6; i ++ ) { - - const distance = planes[ i ].distanceToPoint( center ); - - if ( distance < negRadius ) { - - return false; - - } - - } - - return true; - - } - - intersectsBox( box ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - const plane = planes[ i ]; - - // corner at max distance - - _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x; - _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y; - _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z; - - if ( plane.distanceToPoint( _vector$7 ) < 0 ) { - - return false; - - } - - } - - return true; - - } - - containsPoint( point ) { - - const planes = this.planes; - - for ( let i = 0; i < 6; i ++ ) { - - if ( planes[ i ].distanceToPoint( point ) < 0 ) { - - return false; - - } - - } - - return true; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - } - - function WebGLAnimation() { - - let context = null; - let isAnimating = false; - let animationLoop = null; - let requestId = null; - - function onAnimationFrame( time, frame ) { - - animationLoop( time, frame ); - - requestId = context.requestAnimationFrame( onAnimationFrame ); - - } - - return { - - start: function () { - - if ( isAnimating === true ) return; - if ( animationLoop === null ) return; - - requestId = context.requestAnimationFrame( onAnimationFrame ); - - isAnimating = true; - - }, - - stop: function () { - - context.cancelAnimationFrame( requestId ); - - isAnimating = false; - - }, - - setAnimationLoop: function ( callback ) { - - animationLoop = callback; - - }, - - setContext: function ( value ) { - - context = value; - - } - - }; - - } - - function WebGLAttributes( gl, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - const buffers = new WeakMap(); - - function createBuffer( attribute, bufferType ) { - - const array = attribute.array; - const usage = attribute.usage; - - const buffer = gl.createBuffer(); - - gl.bindBuffer( bufferType, buffer ); - gl.bufferData( bufferType, array, usage ); - - attribute.onUploadCallback(); - - let type = 5126; - - if ( array instanceof Float32Array ) { - - type = 5126; - - } else if ( array instanceof Float64Array ) { - - console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' ); - - } else if ( array instanceof Uint16Array ) { - - if ( attribute.isFloat16BufferAttribute ) { - - if ( isWebGL2 ) { - - type = 5131; - - } else { - - console.warn( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' ); - - } - - } else { - - type = 5123; - - } - - } else if ( array instanceof Int16Array ) { - - type = 5122; - - } else if ( array instanceof Uint32Array ) { - - type = 5125; - - } else if ( array instanceof Int32Array ) { - - type = 5124; - - } else if ( array instanceof Int8Array ) { - - type = 5120; - - } else if ( array instanceof Uint8Array ) { - - type = 5121; - - } else if ( array instanceof Uint8ClampedArray ) { - - type = 5121; - - } - - return { - buffer: buffer, - type: type, - bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version - }; - - } - - function updateBuffer( buffer, attribute, bufferType ) { - - const array = attribute.array; - const updateRange = attribute.updateRange; - - gl.bindBuffer( bufferType, buffer ); - - if ( updateRange.count === - 1 ) { - - // Not using update ranges - - gl.bufferSubData( bufferType, 0, array ); - - } else { - - if ( isWebGL2 ) { - - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array, updateRange.offset, updateRange.count ); - - } else { - - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); - - } - - updateRange.count = - 1; // reset range - - } - - } - - // - - function get( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - return buffers.get( attribute ); - - } - - function remove( attribute ) { - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - const data = buffers.get( attribute ); - - if ( data ) { - - gl.deleteBuffer( data.buffer ); - - buffers.delete( attribute ); - - } - - } - - function update( attribute, bufferType ) { - - if ( attribute.isGLBufferAttribute ) { - - const cached = buffers.get( attribute ); - - if ( ! cached || cached.version < attribute.version ) { - - buffers.set( attribute, { - buffer: attribute.buffer, - type: attribute.type, - bytesPerElement: attribute.elementSize, - version: attribute.version - } ); - - } - - return; - - } - - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; - - const data = buffers.get( attribute ); - - if ( data === undefined ) { - - buffers.set( attribute, createBuffer( attribute, bufferType ) ); - - } else if ( data.version < attribute.version ) { - - updateBuffer( data.buffer, attribute, bufferType ); - - data.version = attribute.version; - - } - - } - - return { - - get: get, - remove: remove, - update: update - - }; - - } - - class PlaneGeometry extends BufferGeometry { - - constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { - - super(); - this.type = 'PlaneGeometry'; - - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; - - const width_half = width / 2; - const height_half = height / 2; - - const gridX = Math.floor( widthSegments ); - const gridY = Math.floor( heightSegments ); - - const gridX1 = gridX + 1; - const gridY1 = gridY + 1; - - const segment_width = width / gridX; - const segment_height = height / gridY; - - // - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - for ( let iy = 0; iy < gridY1; iy ++ ) { - - const y = iy * segment_height - height_half; - - for ( let ix = 0; ix < gridX1; ix ++ ) { - - const x = ix * segment_width - width_half; - - vertices.push( x, - y, 0 ); - - normals.push( 0, 0, 1 ); - - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); - - } - - } - - for ( let iy = 0; iy < gridY; iy ++ ) { - - for ( let ix = 0; ix < gridX; ix ++ ) { - - const a = ix + gridX1 * iy; - const b = ix + gridX1 * ( iy + 1 ); - const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - const d = ( ix + 1 ) + gridX1 * iy; - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - static fromJSON( data ) { - - return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); - - } - - } - - var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif"; - - var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - - var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;\n#endif"; - - var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; - - var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; - - var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - - var begin_vertex = "vec3 transformed = vec3( position );"; - - var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; - - var bsdfs = "vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat V_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_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( V * 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 dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\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.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - 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\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\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_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 dotVH = saturate( dot( geometry.viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float NoH ) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float NoV, float NoL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( NoL + NoV - NoL * NoV ) ) );\n}\nvec3 BRDF_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif"; - - var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\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 ) * faceDirection;\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"; - - var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif"; - - var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; - - var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; - - var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; - - var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; - - var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; - - var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif"; - - var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; - - var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}"; - - var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_maxMipLevel 8.0\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_maxTileSize 256.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tfloat texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 1.0 );\n\t\tvec2 f = fract( uv );\n\t\tuv += 0.5 - f;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tif ( mipInt < cubeUV_maxMipLevel ) {\n\t\t\tuv.y += 2.0 * cubeUV_maxTileSize;\n\t\t}\n\t\tuv.y += filterInt * 2.0 * cubeUV_minTileSize;\n\t\tuv.x += 3.0 * max( 0.0, cubeUV_maxTileSize - 2.0 * faceSize );\n\t\tuv *= texelSize;\n\t\tvec3 tl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x += texelSize;\n\t\tvec3 tr = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.y += texelSize;\n\t\tvec3 br = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x -= texelSize;\n\t\tvec3 bl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tvec3 tm = mix( tl, tr, f.x );\n\t\tvec3 bm = mix( bl, br, f.x );\n\t\treturn mix( tm, bm, f.y );\n\t}\n\t#define r0 1.0\n\t#define v0 0.339\n\t#define m0 - 2.0\n\t#define r1 0.8\n\t#define v1 0.276\n\t#define m1 - 1.0\n\t#define r4 0.4\n\t#define v4 0.046\n\t#define m4 2.0\n\t#define r5 0.305\n\t#define v5 0.016\n\t#define m5 3.0\n\t#define r6 0.21\n\t#define v6 0.0038\n\t#define m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= r1 ) {\n\t\t\tmip = ( r0 - roughness ) * ( m1 - m0 ) / ( r0 - r1 ) + m0;\n\t\t} else if ( roughness >= r4 ) {\n\t\t\tmip = ( r1 - roughness ) * ( m4 - m1 ) / ( r1 - r4 ) + m1;\n\t\t} else if ( roughness >= r5 ) {\n\t\t\tmip = ( r4 - roughness ) * ( m5 - m4 ) / ( r4 - r5 ) + m4;\n\t\t} else if ( roughness >= r6 ) {\n\t\t\tmip = ( r5 - roughness ) * ( m6 - m5 ) / ( r5 - r6 ) + m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), m0, cubeUV_maxMipLevel );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; - - var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; - - var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; - - var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif"; - - var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; - - var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; - - var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; - - var encodings_pars_fragment = "\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = cLogLuvM * value.rgb;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}"; - - var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; - - var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif"; - - var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif"; - - var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif"; - - var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif"; - - var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; - - var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; - - var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"; - - var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif"; - - var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}"; - - var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tlightMapIrradiance *= PI;\n\t#endif\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; - - var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; - - var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\nvIndirectFront += getAmbientLightIrradiance( ambientLightColor );\nvIndirectFront += getLightProbeIrradiance( lightProbe, geometry );\n#ifdef DOUBLE_SIDED\n\tvIndirectBack += getAmbientLightIrradiance( ambientLightColor );\n\tvIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry );\n#endif\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointLightInfo( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotLightInfo( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalLightInfo( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif"; - - var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#else\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; - - var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getIBLIrradiance( const in GeometricContext geometry ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 reflectVec;\n\t\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\t\treflectVec = reflect( - viewDir, normal );\n\t\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\t#else\n\t\t\t\treflectVec = refract( - viewDir, normal, refractionRatio );\n\t\t\t#endif\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n#endif"; - - var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; - - var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)"; - - var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; - - var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)"; - - var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\t#ifdef SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularTintFactor = specularTint;\n\t\t#ifdef USE_SPECULARINTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;\n\t\t#endif\n\t\t#ifdef USE_SPECULARTINTMAP\n\t\t\tspecularTintFactor *= specularTintMapTexelToLinear( texture2D( specularTintMap, vUv ) ).rgb;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularTintFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( ior - 1.0 ) / ( ior + 1.0 ) ) * specularTintFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenTint = sheenTint;\n#endif"; - - var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenTint;\n\t#endif\n};\nvec3 clearcoatSpecular = vec3( 0.0 );\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, 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 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\tvec3 FssEss = specularColor * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecular += ccIrradiance * BRDF_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += irradiance * BRDF_Sheen( material.roughness, directLight.direction, geometry, material.sheenTint );\n\t#else\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness );\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tcomputeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; - - var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef USE_CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; - - var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometry );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness );\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; - - var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif"; - - var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; - - var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; - - var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif"; - - var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; - - var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif"; - - var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; - - var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; - - var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - - var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; - - var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; - - var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif"; - - var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\t\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\t\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif"; - - var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif"; - - var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;"; - - var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; - - var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; - - var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; - - var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; - - var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif"; - - var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif"; - - var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif"; - - var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif"; - - var output_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= transmissionAlpha + 0.1;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; - - var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}"; - - var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; - - var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; - - var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; - - var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; - - var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; - - var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; - - var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; - - var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; - - var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif"; - - var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; - - var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; - - var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform highp sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif"; - - var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; - - var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; - - var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; - - var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; - - var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; - - var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - - var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tfloat transmissionAlpha = 1.0;\n\tfloat transmissionFactor = transmission;\n\tfloat thicknessFactor = thickness;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\ttransmissionFactor *= texture2D( transmissionMap, vUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tthicknessFactor *= texture2D( thicknessMap, vUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmission = getIBLVolumeRefraction(\n\t\tn, v, roughnessFactor, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, ior, thicknessFactor,\n\t\tattenuationTint, attenuationDistance );\n\ttotalDiffuse = mix( totalDiffuse, transmission.rgb, transmissionFactor );\n\ttransmissionAlpha = transmission.a;\n#endif"; - - var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationTint;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tvec3 getVolumeTransmissionRay( vec3 n, vec3 v, float thickness, float ior, mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( float roughness, float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( vec2 fragCoord, float roughness, float ior ) {\n\t\tfloat framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\treturn texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#else\n\t\t\treturn texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#endif\n\t}\n\tvec3 applyVolumeAttenuation( vec3 radiance, float transmissionDistance, vec3 attenuationColor, float attenuationDistance ) {\n\t\tif ( attenuationDistance == 0.0 ) {\n\t\t\treturn radiance;\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance * radiance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 specularColor, float specularF90,\n\t\tvec3 position, mat4 modelMatrix, mat4 viewMatrix, mat4 projMatrix, float ior, float thickness,\n\t\tvec3 attenuationColor, float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n\t}\n#endif"; - - var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif"; - - var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif"; - - var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif"; - - var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; - - var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif"; - - var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif"; - - var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; - - var background_frag = "uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}"; - - var background_vert = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; - - var cube_frag = "#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; - - var cube_vert = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - - var depth_frag = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; - - var depth_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; - - var distanceRGBA_frag = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; - - var distanceRGBA_vert = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; - - var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}"; - - var equirect_vert = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; - - var linedashed_frag = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshbasic_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshbasic_vert = "#include \n#include \n#include \n#include \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#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \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#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshmatcap_frag = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshmatcap_vert = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \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#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; - - var meshnormal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \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#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}"; - - var meshnormal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \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#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; - - var meshphong_frag = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \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#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshphysical_frag = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularTint;\n\t#ifdef USE_SPECULARINTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n\t#ifdef USE_SPECULARTINTMAP\n\t\tuniform sampler2D specularTintMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenTint;\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - clearcoat * Fcc ) + clearcoatSpecular * clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshphysical_vert = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \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#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; - - var meshtoon_frag = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var meshtoon_vert = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \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#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; - - var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\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\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var 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#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var 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\t#include \n\t#include \n}"; - - var shadow_vert = "#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var sprite_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\t#include \n\t#include \n\t#include \n\t#include \n}"; - - var sprite_vert = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; - - const ShaderChunk = { - alphamap_fragment: alphamap_fragment, - alphamap_pars_fragment: alphamap_pars_fragment, - alphatest_fragment: alphatest_fragment, - alphatest_pars_fragment: alphatest_pars_fragment, - aomap_fragment: aomap_fragment, - aomap_pars_fragment: aomap_pars_fragment, - begin_vertex: begin_vertex, - beginnormal_vertex: beginnormal_vertex, - bsdfs: bsdfs, - bumpmap_pars_fragment: bumpmap_pars_fragment, - clipping_planes_fragment: clipping_planes_fragment, - clipping_planes_pars_fragment: clipping_planes_pars_fragment, - clipping_planes_pars_vertex: clipping_planes_pars_vertex, - clipping_planes_vertex: clipping_planes_vertex, - color_fragment: color_fragment, - color_pars_fragment: color_pars_fragment, - color_pars_vertex: color_pars_vertex, - color_vertex: color_vertex, - common: common, - cube_uv_reflection_fragment: cube_uv_reflection_fragment, - defaultnormal_vertex: defaultnormal_vertex, - displacementmap_pars_vertex: displacementmap_pars_vertex, - displacementmap_vertex: displacementmap_vertex, - emissivemap_fragment: emissivemap_fragment, - emissivemap_pars_fragment: emissivemap_pars_fragment, - encodings_fragment: encodings_fragment, - encodings_pars_fragment: encodings_pars_fragment, - envmap_fragment: envmap_fragment, - envmap_common_pars_fragment: envmap_common_pars_fragment, - envmap_pars_fragment: envmap_pars_fragment, - envmap_pars_vertex: envmap_pars_vertex, - envmap_physical_pars_fragment: envmap_physical_pars_fragment, - envmap_vertex: envmap_vertex, - fog_vertex: fog_vertex, - fog_pars_vertex: fog_pars_vertex, - fog_fragment: fog_fragment, - fog_pars_fragment: fog_pars_fragment, - gradientmap_pars_fragment: gradientmap_pars_fragment, - lightmap_fragment: lightmap_fragment, - lightmap_pars_fragment: lightmap_pars_fragment, - lights_lambert_vertex: lights_lambert_vertex, - lights_pars_begin: lights_pars_begin, - lights_toon_fragment: lights_toon_fragment, - lights_toon_pars_fragment: lights_toon_pars_fragment, - lights_phong_fragment: lights_phong_fragment, - lights_phong_pars_fragment: lights_phong_pars_fragment, - lights_physical_fragment: lights_physical_fragment, - lights_physical_pars_fragment: lights_physical_pars_fragment, - lights_fragment_begin: lights_fragment_begin, - lights_fragment_maps: lights_fragment_maps, - lights_fragment_end: lights_fragment_end, - logdepthbuf_fragment: logdepthbuf_fragment, - logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, - logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, - logdepthbuf_vertex: logdepthbuf_vertex, - map_fragment: map_fragment, - map_pars_fragment: map_pars_fragment, - map_particle_fragment: map_particle_fragment, - map_particle_pars_fragment: map_particle_pars_fragment, - metalnessmap_fragment: metalnessmap_fragment, - metalnessmap_pars_fragment: metalnessmap_pars_fragment, - morphnormal_vertex: morphnormal_vertex, - morphtarget_pars_vertex: morphtarget_pars_vertex, - morphtarget_vertex: morphtarget_vertex, - normal_fragment_begin: normal_fragment_begin, - normal_fragment_maps: normal_fragment_maps, - normal_pars_fragment: normal_pars_fragment, - normal_pars_vertex: normal_pars_vertex, - normal_vertex: normal_vertex, - normalmap_pars_fragment: normalmap_pars_fragment, - clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, - clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, - clearcoat_pars_fragment: clearcoat_pars_fragment, - output_fragment: output_fragment, - packing: packing, - premultiplied_alpha_fragment: premultiplied_alpha_fragment, - project_vertex: project_vertex, - dithering_fragment: dithering_fragment, - dithering_pars_fragment: dithering_pars_fragment, - roughnessmap_fragment: roughnessmap_fragment, - roughnessmap_pars_fragment: roughnessmap_pars_fragment, - shadowmap_pars_fragment: shadowmap_pars_fragment, - shadowmap_pars_vertex: shadowmap_pars_vertex, - shadowmap_vertex: shadowmap_vertex, - shadowmask_pars_fragment: shadowmask_pars_fragment, - skinbase_vertex: skinbase_vertex, - skinning_pars_vertex: skinning_pars_vertex, - skinning_vertex: skinning_vertex, - skinnormal_vertex: skinnormal_vertex, - specularmap_fragment: specularmap_fragment, - specularmap_pars_fragment: specularmap_pars_fragment, - tonemapping_fragment: tonemapping_fragment, - tonemapping_pars_fragment: tonemapping_pars_fragment, - transmission_fragment: transmission_fragment, - transmission_pars_fragment: transmission_pars_fragment, - uv_pars_fragment: uv_pars_fragment, - uv_pars_vertex: uv_pars_vertex, - uv_vertex: uv_vertex, - uv2_pars_fragment: uv2_pars_fragment, - uv2_pars_vertex: uv2_pars_vertex, - uv2_vertex: uv2_vertex, - worldpos_vertex: worldpos_vertex, - - background_frag: background_frag, - background_vert: background_vert, - cube_frag: cube_frag, - cube_vert: cube_vert, - depth_frag: depth_frag, - depth_vert: depth_vert, - distanceRGBA_frag: distanceRGBA_frag, - distanceRGBA_vert: distanceRGBA_vert, - equirect_frag: equirect_frag, - equirect_vert: equirect_vert, - linedashed_frag: linedashed_frag, - linedashed_vert: linedashed_vert, - meshbasic_frag: meshbasic_frag, - meshbasic_vert: meshbasic_vert, - meshlambert_frag: meshlambert_frag, - meshlambert_vert: meshlambert_vert, - meshmatcap_frag: meshmatcap_frag, - meshmatcap_vert: meshmatcap_vert, - meshnormal_frag: meshnormal_frag, - meshnormal_vert: meshnormal_vert, - meshphong_frag: meshphong_frag, - meshphong_vert: meshphong_vert, - meshphysical_frag: meshphysical_frag, - meshphysical_vert: meshphysical_vert, - meshtoon_frag: meshtoon_frag, - meshtoon_vert: meshtoon_vert, - points_frag: points_frag, - points_vert: points_vert, - shadow_frag: shadow_frag, - shadow_vert: shadow_vert, - sprite_frag: sprite_frag, - sprite_vert: sprite_vert - }; - - /** - * Uniforms library for shared webgl shaders - */ - - const UniformsLib = { - - common: { - - diffuse: { value: new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - - map: { value: null }, - uvTransform: { value: new Matrix3() }, - uv2Transform: { value: new Matrix3() }, - - alphaMap: { value: null }, - alphaTest: { value: 0 } - - }, - - specularmap: { - - specularMap: { value: null }, - - }, - - envmap: { - - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - reflectivity: { value: 1.0 }, // basic, lambert, phong - ior: { value: 1.5 }, // standard, physical - refractionRatio: { value: 0.98 }, - maxMipLevel: { value: 0 } - - }, - - aomap: { - - aoMap: { value: null }, - aoMapIntensity: { value: 1 } - - }, - - lightmap: { - - lightMap: { value: null }, - lightMapIntensity: { value: 1 } - - }, - - emissivemap: { - - emissiveMap: { value: null } - - }, - - bumpmap: { - - bumpMap: { value: null }, - bumpScale: { value: 1 } - - }, - - normalmap: { - - normalMap: { value: null }, - normalScale: { value: new Vector2( 1, 1 ) } - - }, - - displacementmap: { - - displacementMap: { value: null }, - displacementScale: { value: 1 }, - displacementBias: { value: 0 } - - }, - - roughnessmap: { - - roughnessMap: { value: null } - - }, - - metalnessmap: { - - metalnessMap: { value: null } - - }, - - gradientmap: { - - gradientMap: { value: null } - - }, - - fog: { - - fogDensity: { value: 0.00025 }, - fogNear: { value: 1 }, - fogFar: { value: 2000 }, - fogColor: { value: new Color( 0xffffff ) } - - }, - - lights: { - - ambientLightColor: { value: [] }, - - lightProbe: { value: [] }, - - directionalLights: { value: [], properties: { - direction: {}, - color: {} - } }, - - directionalLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - directionalShadowMap: { value: [] }, - directionalShadowMatrix: { value: [] }, - - spotLights: { value: [], properties: { - color: {}, - position: {}, - direction: {}, - distance: {}, - coneCos: {}, - penumbraCos: {}, - decay: {} - } }, - - spotLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, - - spotShadowMap: { value: [] }, - spotShadowMatrix: { value: [] }, - - pointLights: { value: [], properties: { - color: {}, - position: {}, - decay: {}, - distance: {} - } }, - - pointLightShadows: { value: [], properties: { - shadowBias: {}, - shadowNormalBias: {}, - shadowRadius: {}, - shadowMapSize: {}, - shadowCameraNear: {}, - shadowCameraFar: {} - } }, - - pointShadowMap: { value: [] }, - pointShadowMatrix: { value: [] }, - - hemisphereLights: { value: [], properties: { - direction: {}, - skyColor: {}, - groundColor: {} - } }, - - // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src - rectAreaLights: { value: [], properties: { - color: {}, - position: {}, - width: {}, - height: {} - } }, - - ltc_1: { value: null }, - ltc_2: { value: null } - - }, - - points: { - - diffuse: { value: new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - size: { value: 1.0 }, - scale: { value: 1.0 }, - map: { value: null }, - alphaMap: { value: null }, - alphaTest: { value: 0 }, - uvTransform: { value: new Matrix3() } - - }, - - sprite: { - - diffuse: { value: new Color( 0xffffff ) }, - opacity: { value: 1.0 }, - center: { value: new Vector2( 0.5, 0.5 ) }, - rotation: { value: 0.0 }, - map: { value: null }, - alphaMap: { value: null }, - alphaTest: { value: 0 }, - uvTransform: { value: new Matrix3() } - - } - - }; - - const ShaderLib = { - - basic: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.meshbasic_vert, - fragmentShader: ShaderChunk.meshbasic_frag - - }, - - lambert: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) } - } - ] ), - - vertexShader: ShaderChunk.meshlambert_vert, - fragmentShader: ShaderChunk.meshlambert_frag - - }, - - phong: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) }, - specular: { value: new Color( 0x111111 ) }, - shininess: { value: 30 } - } - ] ), - - vertexShader: ShaderChunk.meshphong_vert, - fragmentShader: ShaderChunk.meshphong_frag - - }, - - standard: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.roughnessmap, - UniformsLib.metalnessmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) }, - roughness: { value: 1.0 }, - metalness: { value: 0.0 }, - envMapIntensity: { value: 1 } // temporary - } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - - }, - - toon: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.gradientmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) } - } - ] ), - - vertexShader: ShaderChunk.meshtoon_vert, - fragmentShader: ShaderChunk.meshtoon_frag - - }, - - matcap: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - { - matcap: { value: null } - } - ] ), - - vertexShader: ShaderChunk.meshmatcap_vert, - fragmentShader: ShaderChunk.meshmatcap_frag - - }, - - points: { - - uniforms: mergeUniforms( [ - UniformsLib.points, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.points_vert, - fragmentShader: ShaderChunk.points_frag - - }, - - dashed: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.fog, - { - scale: { value: 1 }, - dashSize: { value: 1 }, - totalSize: { value: 2 } - } - ] ), - - vertexShader: ShaderChunk.linedashed_vert, - fragmentShader: ShaderChunk.linedashed_frag - - }, - - depth: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.displacementmap - ] ), - - vertexShader: ShaderChunk.depth_vert, - fragmentShader: ShaderChunk.depth_frag - - }, - - normal: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - { - opacity: { value: 1.0 } - } - ] ), - - vertexShader: ShaderChunk.meshnormal_vert, - fragmentShader: ShaderChunk.meshnormal_frag - - }, - - sprite: { - - uniforms: mergeUniforms( [ - UniformsLib.sprite, - UniformsLib.fog - ] ), - - vertexShader: ShaderChunk.sprite_vert, - fragmentShader: ShaderChunk.sprite_frag - - }, - - background: { - - uniforms: { - uvTransform: { value: new Matrix3() }, - t2D: { value: null }, - }, - - vertexShader: ShaderChunk.background_vert, - fragmentShader: ShaderChunk.background_frag - - }, - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ - - cube: { - - uniforms: mergeUniforms( [ - UniformsLib.envmap, - { - opacity: { value: 1.0 } - } - ] ), - - vertexShader: ShaderChunk.cube_vert, - fragmentShader: ShaderChunk.cube_frag - - }, - - equirect: { - - uniforms: { - tEquirect: { value: null }, - }, - - vertexShader: ShaderChunk.equirect_vert, - fragmentShader: ShaderChunk.equirect_frag - - }, - - distanceRGBA: { - - uniforms: mergeUniforms( [ - UniformsLib.common, - UniformsLib.displacementmap, - { - referencePosition: { value: new Vector3() }, - nearDistance: { value: 1 }, - farDistance: { value: 1000 } - } - ] ), - - vertexShader: ShaderChunk.distanceRGBA_vert, - fragmentShader: ShaderChunk.distanceRGBA_frag - - }, - - shadow: { - - uniforms: mergeUniforms( [ - UniformsLib.lights, - UniformsLib.fog, - { - color: { value: new Color( 0x00000 ) }, - opacity: { value: 1.0 } - }, - ] ), - - vertexShader: ShaderChunk.shadow_vert, - fragmentShader: ShaderChunk.shadow_frag - - } - - }; - - ShaderLib.physical = { - - uniforms: mergeUniforms( [ - ShaderLib.standard.uniforms, - { - clearcoat: { value: 0 }, - clearcoatMap: { value: null }, - clearcoatRoughness: { value: 0 }, - clearcoatRoughnessMap: { value: null }, - clearcoatNormalScale: { value: new Vector2( 1, 1 ) }, - clearcoatNormalMap: { value: null }, - sheenTint: { value: new Color( 0x000000 ) }, - transmission: { value: 0 }, - transmissionMap: { value: null }, - transmissionSamplerSize: { value: new Vector2() }, - transmissionSamplerMap: { value: null }, - thickness: { value: 0 }, - thicknessMap: { value: null }, - attenuationDistance: { value: 0 }, - attenuationTint: { value: new Color( 0x000000 ) }, - specularIntensity: { value: 0 }, - specularIntensityMap: { value: null }, - specularTint: { value: new Color( 1, 1, 1 ) }, - specularTintMap: { value: null }, - } - ] ), - - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag - - }; - - function WebGLBackground( renderer, cubemaps, state, objects, premultipliedAlpha ) { - - const clearColor = new Color( 0x000000 ); - let clearAlpha = 0; - - let planeMesh; - let boxMesh; - - let currentBackground = null; - let currentBackgroundVersion = 0; - let currentTonemapping = null; - - function render( renderList, scene ) { - - let forceClear = false; - let background = scene.isScene === true ? scene.background : null; - - if ( background && background.isTexture ) { - - background = cubemaps.get( background ); - - } - - // Ignore background in AR - // TODO: Reconsider this. - - const xr = renderer.xr; - const session = xr.getSession && xr.getSession(); - - if ( session && session.environmentBlendMode === 'additive' ) { - - background = null; - - } - - if ( background === null ) { - - setClear( clearColor, clearAlpha ); - - } else if ( background && background.isColor ) { - - setClear( background, 1 ); - forceClear = true; - - } - - if ( renderer.autoClear || forceClear ) { - - renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); - - } - - if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) { - - if ( boxMesh === undefined ) { - - boxMesh = new Mesh( - new BoxGeometry( 1, 1, 1 ), - new ShaderMaterial( { - name: 'BackgroundCubeMaterial', - uniforms: cloneUniforms( ShaderLib.cube.uniforms ), - vertexShader: ShaderLib.cube.vertexShader, - fragmentShader: ShaderLib.cube.fragmentShader, - side: BackSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); - - boxMesh.geometry.deleteAttribute( 'normal' ); - boxMesh.geometry.deleteAttribute( 'uv' ); - - boxMesh.onBeforeRender = function ( renderer, scene, camera ) { - - this.matrixWorld.copyPosition( camera.matrixWorld ); - - }; - - // enable code injection for non-built-in material - Object.defineProperty( boxMesh.material, 'envMap', { - - get: function () { - - return this.uniforms.envMap.value; - - } - - } ); - - objects.update( boxMesh ); - - } - - boxMesh.material.uniforms.envMap.value = background; - boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1; - - if ( currentBackground !== background || - currentBackgroundVersion !== background.version || - currentTonemapping !== renderer.toneMapping ) { - - boxMesh.material.needsUpdate = true; - - currentBackground = background; - currentBackgroundVersion = background.version; - currentTonemapping = renderer.toneMapping; - - } - - // push to the pre-sorted opaque render list - renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null ); - - } else if ( background && background.isTexture ) { - - if ( planeMesh === undefined ) { - - planeMesh = new Mesh( - new PlaneGeometry( 2, 2 ), - new ShaderMaterial( { - name: 'BackgroundMaterial', - uniforms: cloneUniforms( ShaderLib.background.uniforms ), - vertexShader: ShaderLib.background.vertexShader, - fragmentShader: ShaderLib.background.fragmentShader, - side: FrontSide, - depthTest: false, - depthWrite: false, - fog: false - } ) - ); - - planeMesh.geometry.deleteAttribute( 'normal' ); - - // enable code injection for non-built-in material - Object.defineProperty( planeMesh.material, 'map', { - - get: function () { - - return this.uniforms.t2D.value; - - } - - } ); - - objects.update( planeMesh ); - - } - - planeMesh.material.uniforms.t2D.value = background; - - if ( background.matrixAutoUpdate === true ) { - - background.updateMatrix(); - - } - - planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); - - if ( currentBackground !== background || - currentBackgroundVersion !== background.version || - currentTonemapping !== renderer.toneMapping ) { - - planeMesh.material.needsUpdate = true; - - currentBackground = background; - currentBackgroundVersion = background.version; - currentTonemapping = renderer.toneMapping; - - } - - - // push to the pre-sorted opaque render list - renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null ); - - } - - } - - function setClear( color, alpha ) { - - state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha ); - - } - - return { - - getClearColor: function () { - - return clearColor; - - }, - setClearColor: function ( color, alpha = 1 ) { - - clearColor.set( color ); - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); - - }, - getClearAlpha: function () { - - return clearAlpha; - - }, - setClearAlpha: function ( alpha ) { - - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); - - }, - render: render - - }; - - } - - function WebGLBindingStates( gl, extensions, attributes, capabilities ) { - - const maxVertexAttributes = gl.getParameter( 34921 ); - - const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); - const vaoAvailable = capabilities.isWebGL2 || extension !== null; - - const bindingStates = {}; - - const defaultState = createBindingState( null ); - let currentState = defaultState; - - function setup( object, material, program, geometry, index ) { - - let updateBuffers = false; - - if ( vaoAvailable ) { - - const state = getBindingState( geometry, program, material ); - - if ( currentState !== state ) { - - currentState = state; - bindVertexArrayObject( currentState.object ); - - } - - updateBuffers = needsUpdate( geometry, index ); - - if ( updateBuffers ) saveCache( geometry, index ); - - } else { - - const wireframe = ( material.wireframe === true ); - - if ( currentState.geometry !== geometry.id || - currentState.program !== program.id || - currentState.wireframe !== wireframe ) { - - currentState.geometry = geometry.id; - currentState.program = program.id; - currentState.wireframe = wireframe; - - updateBuffers = true; - - } - - } - - if ( object.isInstancedMesh === true ) { - - updateBuffers = true; - - } - - if ( index !== null ) { - - attributes.update( index, 34963 ); - - } - - if ( updateBuffers ) { - - setupVertexAttributes( object, material, program, geometry ); - - if ( index !== null ) { - - gl.bindBuffer( 34963, attributes.get( index ).buffer ); - - } - - } - - } - - function createVertexArrayObject() { - - if ( capabilities.isWebGL2 ) return gl.createVertexArray(); - - return extension.createVertexArrayOES(); - - } - - function bindVertexArrayObject( vao ) { - - if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao ); - - return extension.bindVertexArrayOES( vao ); - - } - - function deleteVertexArrayObject( vao ) { - - if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao ); - - return extension.deleteVertexArrayOES( vao ); - - } - - function getBindingState( geometry, program, material ) { - - const wireframe = ( material.wireframe === true ); - - let programMap = bindingStates[ geometry.id ]; - - if ( programMap === undefined ) { - - programMap = {}; - bindingStates[ geometry.id ] = programMap; - - } - - let stateMap = programMap[ program.id ]; - - if ( stateMap === undefined ) { - - stateMap = {}; - programMap[ program.id ] = stateMap; - - } - - let state = stateMap[ wireframe ]; - - if ( state === undefined ) { - - state = createBindingState( createVertexArrayObject() ); - stateMap[ wireframe ] = state; - - } - - return state; - - } - - function createBindingState( vao ) { - - const newAttributes = []; - const enabledAttributes = []; - const attributeDivisors = []; - - for ( let i = 0; i < maxVertexAttributes; i ++ ) { - - newAttributes[ i ] = 0; - enabledAttributes[ i ] = 0; - attributeDivisors[ i ] = 0; - - } - - return { - - // for backward compatibility on non-VAO support browser - geometry: null, - program: null, - wireframe: false, - - newAttributes: newAttributes, - enabledAttributes: enabledAttributes, - attributeDivisors: attributeDivisors, - object: vao, - attributes: {}, - index: null - - }; - - } - - function needsUpdate( geometry, index ) { - - const cachedAttributes = currentState.attributes; - const geometryAttributes = geometry.attributes; - - let attributesNum = 0; - - for ( const key in geometryAttributes ) { - - const cachedAttribute = cachedAttributes[ key ]; - const geometryAttribute = geometryAttributes[ key ]; - - if ( cachedAttribute === undefined ) return true; - - if ( cachedAttribute.attribute !== geometryAttribute ) return true; - - if ( cachedAttribute.data !== geometryAttribute.data ) return true; - - attributesNum ++; - - } - - if ( currentState.attributesNum !== attributesNum ) return true; - - if ( currentState.index !== index ) return true; - - return false; - - } - - function saveCache( geometry, index ) { - - const cache = {}; - const attributes = geometry.attributes; - let attributesNum = 0; - - for ( const key in attributes ) { - - const attribute = attributes[ key ]; - - const data = {}; - data.attribute = attribute; - - if ( attribute.data ) { - - data.data = attribute.data; - - } - - cache[ key ] = data; - - attributesNum ++; - - } - - currentState.attributes = cache; - currentState.attributesNum = attributesNum; - - currentState.index = index; - - } - - function initAttributes() { - - const newAttributes = currentState.newAttributes; - - for ( let i = 0, il = newAttributes.length; i < il; i ++ ) { - - newAttributes[ i ] = 0; - - } - - } - - function enableAttribute( attribute ) { - - enableAttributeAndDivisor( attribute, 0 ); - - } - - function enableAttributeAndDivisor( attribute, meshPerAttribute ) { - - const newAttributes = currentState.newAttributes; - const enabledAttributes = currentState.enabledAttributes; - const attributeDivisors = currentState.attributeDivisors; - - newAttributes[ attribute ] = 1; - - if ( enabledAttributes[ attribute ] === 0 ) { - - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; - - } - - if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { - - const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); - - extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); - attributeDivisors[ attribute ] = meshPerAttribute; - - } - - } - - function disableUnusedAttributes() { - - const newAttributes = currentState.newAttributes; - const enabledAttributes = currentState.enabledAttributes; - - for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) { - - if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; - - } - - } - - } - - function vertexAttribPointer( index, size, type, normalized, stride, offset ) { - - if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) { - - gl.vertexAttribIPointer( index, size, type, stride, offset ); - - } else { - - gl.vertexAttribPointer( index, size, type, normalized, stride, offset ); - - } - - } - - function setupVertexAttributes( object, material, program, geometry ) { - - if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) { - - if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return; - - } - - initAttributes(); - - const geometryAttributes = geometry.attributes; - - const programAttributes = program.getAttributes(); - - const materialDefaultAttributeValues = material.defaultAttributeValues; - - for ( const name in programAttributes ) { - - const programAttribute = programAttributes[ name ]; - - if ( programAttribute.location >= 0 ) { - - let geometryAttribute = geometryAttributes[ name ]; - - if ( geometryAttribute === undefined ) { - - if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; - if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; - - } - - if ( geometryAttribute !== undefined ) { - - const normalized = geometryAttribute.normalized; - const size = geometryAttribute.itemSize; - - const attribute = attributes.get( geometryAttribute ); - - // TODO Attribute may not be available on context restore - - if ( attribute === undefined ) continue; - - const buffer = attribute.buffer; - const type = attribute.type; - const bytesPerElement = attribute.bytesPerElement; - - if ( geometryAttribute.isInterleavedBufferAttribute ) { - - const data = geometryAttribute.data; - const stride = data.stride; - const offset = geometryAttribute.offset; - - if ( data && data.isInstancedInterleavedBuffer ) { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute ); - - } - - if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { - - geometry._maxInstanceCount = data.meshPerAttribute * data.count; - - } - - } else { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttribute( programAttribute.location + i ); - - } - - } - - gl.bindBuffer( 34962, buffer ); - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - vertexAttribPointer( - programAttribute.location + i, - size / programAttribute.locationSize, - type, - normalized, - stride * bytesPerElement, - ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement - ); - - } - - } else { - - if ( geometryAttribute.isInstancedBufferAttribute ) { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute ); - - } - - if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { - - geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; - - } - - } else { - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - enableAttribute( programAttribute.location + i ); - - } - - } - - gl.bindBuffer( 34962, buffer ); - - for ( let i = 0; i < programAttribute.locationSize; i ++ ) { - - vertexAttribPointer( - programAttribute.location + i, - size / programAttribute.locationSize, - type, - normalized, - size * bytesPerElement, - ( size / programAttribute.locationSize ) * i * bytesPerElement - ); - - } - - } - - } else if ( materialDefaultAttributeValues !== undefined ) { - - const value = materialDefaultAttributeValues[ name ]; - - if ( value !== undefined ) { - - switch ( value.length ) { - - case 2: - gl.vertexAttrib2fv( programAttribute.location, value ); - break; - - case 3: - gl.vertexAttrib3fv( programAttribute.location, value ); - break; - - case 4: - gl.vertexAttrib4fv( programAttribute.location, value ); - break; - - default: - gl.vertexAttrib1fv( programAttribute.location, value ); - - } - - } - - } - - } - - } - - disableUnusedAttributes(); - - } - - function dispose() { - - reset(); - - for ( const geometryId in bindingStates ) { - - const programMap = bindingStates[ geometryId ]; - - for ( const programId in programMap ) { - - const stateMap = programMap[ programId ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ programId ]; - - } - - delete bindingStates[ geometryId ]; - - } - - } - - function releaseStatesOfGeometry( geometry ) { - - if ( bindingStates[ geometry.id ] === undefined ) return; - - const programMap = bindingStates[ geometry.id ]; - - for ( const programId in programMap ) { - - const stateMap = programMap[ programId ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ programId ]; - - } - - delete bindingStates[ geometry.id ]; - - } - - function releaseStatesOfProgram( program ) { - - for ( const geometryId in bindingStates ) { - - const programMap = bindingStates[ geometryId ]; - - if ( programMap[ program.id ] === undefined ) continue; - - const stateMap = programMap[ program.id ]; - - for ( const wireframe in stateMap ) { - - deleteVertexArrayObject( stateMap[ wireframe ].object ); - - delete stateMap[ wireframe ]; - - } - - delete programMap[ program.id ]; - - } - - } - - function reset() { - - resetDefaultState(); - - if ( currentState === defaultState ) return; - - currentState = defaultState; - bindVertexArrayObject( currentState.object ); - - } - - // for backward-compatilibity - - function resetDefaultState() { - - defaultState.geometry = null; - defaultState.program = null; - defaultState.wireframe = false; - - } - - return { - - setup: setup, - reset: reset, - resetDefaultState: resetDefaultState, - dispose: dispose, - releaseStatesOfGeometry: releaseStatesOfGeometry, - releaseStatesOfProgram: releaseStatesOfProgram, - - initAttributes: initAttributes, - enableAttribute: enableAttribute, - disableUnusedAttributes: disableUnusedAttributes - - }; - - } - - function WebGLBufferRenderer( gl, extensions, info, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - let mode; - - function setMode( value ) { - - mode = value; - - } - - function render( start, count ) { - - gl.drawArrays( mode, start, count ); - - info.update( count, mode, 1 ); - - } - - function renderInstances( start, count, primcount ) { - - if ( primcount === 0 ) return; - - let extension, methodName; - - if ( isWebGL2 ) { - - extension = gl; - methodName = 'drawArraysInstanced'; - - } else { - - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawArraysInstancedANGLE'; - - if ( extension === null ) { - - console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - } - - extension[ methodName ]( mode, start, count, primcount ); - - info.update( count, mode, primcount ); - - } - - // - - this.setMode = setMode; - this.render = render; - this.renderInstances = renderInstances; - - } - - function WebGLCapabilities( gl, extensions, parameters ) { - - let maxAnisotropy; - - function getMaxAnisotropy() { - - if ( maxAnisotropy !== undefined ) return maxAnisotropy; - - if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { - - const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); - - } else { - - maxAnisotropy = 0; - - } - - return maxAnisotropy; - - } - - function getMaxPrecision( precision ) { - - if ( precision === 'highp' ) { - - if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { - - return 'highp'; - - } - - precision = 'mediump'; - - } - - if ( precision === 'mediump' ) { - - if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { - - return 'mediump'; - - } - - } - - return 'lowp'; - - } - - /* eslint-disable no-undef */ - const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) || - ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext ); - /* eslint-enable no-undef */ - - let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; - const maxPrecision = getMaxPrecision( precision ); - - if ( maxPrecision !== precision ) { - - console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); - precision = maxPrecision; - - } - - const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ); - - const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; - - const maxTextures = gl.getParameter( 34930 ); - const maxVertexTextures = gl.getParameter( 35660 ); - const maxTextureSize = gl.getParameter( 3379 ); - const maxCubemapSize = gl.getParameter( 34076 ); - - const maxAttributes = gl.getParameter( 34921 ); - const maxVertexUniforms = gl.getParameter( 36347 ); - const maxVaryings = gl.getParameter( 36348 ); - const maxFragmentUniforms = gl.getParameter( 36349 ); - - const vertexTextures = maxVertexTextures > 0; - const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); - const floatVertexTextures = vertexTextures && floatFragmentTextures; - - const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0; - - return { - - isWebGL2: isWebGL2, - - drawBuffers: drawBuffers, - - getMaxAnisotropy: getMaxAnisotropy, - getMaxPrecision: getMaxPrecision, - - precision: precision, - logarithmicDepthBuffer: logarithmicDepthBuffer, - - maxTextures: maxTextures, - maxVertexTextures: maxVertexTextures, - maxTextureSize: maxTextureSize, - maxCubemapSize: maxCubemapSize, - - maxAttributes: maxAttributes, - maxVertexUniforms: maxVertexUniforms, - maxVaryings: maxVaryings, - maxFragmentUniforms: maxFragmentUniforms, - - vertexTextures: vertexTextures, - floatFragmentTextures: floatFragmentTextures, - floatVertexTextures: floatVertexTextures, - - maxSamples: maxSamples - - }; - - } - - function WebGLClipping( properties ) { - - const scope = this; - - let globalState = null, - numGlobalPlanes = 0, - localClippingEnabled = false, - renderingShadows = false; - - const plane = new Plane(), - viewNormalMatrix = new Matrix3(), - - uniform = { value: null, needsUpdate: false }; - - this.uniform = uniform; - this.numPlanes = 0; - this.numIntersection = 0; - - this.init = function ( planes, enableLocalClipping, camera ) { - - const enabled = - planes.length !== 0 || - enableLocalClipping || - // enable state of previous frame - the clipping code has to - // run another frame in order to reset the state: - numGlobalPlanes !== 0 || - localClippingEnabled; - - localClippingEnabled = enableLocalClipping; - - globalState = projectPlanes( planes, camera, 0 ); - numGlobalPlanes = planes.length; - - return enabled; - - }; - - this.beginShadows = function () { - - renderingShadows = true; - projectPlanes( null ); - - }; - - this.endShadows = function () { - - renderingShadows = false; - resetGlobalState(); - - }; - - this.setState = function ( material, camera, useCache ) { - - const planes = material.clippingPlanes, - clipIntersection = material.clipIntersection, - clipShadows = material.clipShadows; - - const materialProperties = properties.get( material ); - - if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { - - // there's no local clipping - - if ( renderingShadows ) { - - // there's no global clipping - - projectPlanes( null ); - - } else { - - resetGlobalState(); - - } - - } else { - - const nGlobal = renderingShadows ? 0 : numGlobalPlanes, - lGlobal = nGlobal * 4; - - let dstArray = materialProperties.clippingState || null; - - uniform.value = dstArray; // ensure unique state - - dstArray = projectPlanes( planes, camera, lGlobal, useCache ); - - for ( let i = 0; i !== lGlobal; ++ i ) { - - dstArray[ i ] = globalState[ i ]; - - } - - materialProperties.clippingState = dstArray; - this.numIntersection = clipIntersection ? this.numPlanes : 0; - this.numPlanes += nGlobal; - - } - - - }; - - function resetGlobalState() { - - if ( uniform.value !== globalState ) { - - uniform.value = globalState; - uniform.needsUpdate = numGlobalPlanes > 0; - - } - - scope.numPlanes = numGlobalPlanes; - scope.numIntersection = 0; - - } - - function projectPlanes( planes, camera, dstOffset, skipTransform ) { - - const nPlanes = planes !== null ? planes.length : 0; - let dstArray = null; - - if ( nPlanes !== 0 ) { - - dstArray = uniform.value; - - if ( skipTransform !== true || dstArray === null ) { - - const flatSize = dstOffset + nPlanes * 4, - viewMatrix = camera.matrixWorldInverse; - - viewNormalMatrix.getNormalMatrix( viewMatrix ); - - if ( dstArray === null || dstArray.length < flatSize ) { - - dstArray = new Float32Array( flatSize ); - - } - - for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { - - plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); - - plane.normal.toArray( dstArray, i4 ); - dstArray[ i4 + 3 ] = plane.constant; - - } - - } - - uniform.value = dstArray; - uniform.needsUpdate = true; - - } - - scope.numPlanes = nPlanes; - scope.numIntersection = 0; - - return dstArray; - - } - - } - - function WebGLCubeMaps( renderer ) { - - let cubemaps = new WeakMap(); - - function mapTextureMapping( texture, mapping ) { - - if ( mapping === EquirectangularReflectionMapping ) { - - texture.mapping = CubeReflectionMapping; - - } else if ( mapping === EquirectangularRefractionMapping ) { - - texture.mapping = CubeRefractionMapping; - - } - - return texture; - - } - - function get( texture ) { - - if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) { - - const mapping = texture.mapping; - - if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { - - if ( cubemaps.has( texture ) ) { - - const cubemap = cubemaps.get( texture ).texture; - return mapTextureMapping( cubemap, texture.mapping ); - - } else { - - const image = texture.image; - - if ( image && image.height > 0 ) { - - const currentRenderTarget = renderer.getRenderTarget(); - - const renderTarget = new WebGLCubeRenderTarget( image.height / 2 ); - renderTarget.fromEquirectangularTexture( renderer, texture ); - cubemaps.set( texture, renderTarget ); - - renderer.setRenderTarget( currentRenderTarget ); - - texture.addEventListener( 'dispose', onTextureDispose ); - - return mapTextureMapping( renderTarget.texture, texture.mapping ); - - } else { - - // image not yet ready. try the conversion next frame - - return null; - - } - - } - - } - - } - - return texture; - - } - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - const cubemap = cubemaps.get( texture ); - - if ( cubemap !== undefined ) { - - cubemaps.delete( texture ); - cubemap.dispose(); - - } - - } - - function dispose() { - - cubemaps = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - - } - - class OrthographicCamera extends Camera { - - constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { - - super(); - - this.type = 'OrthographicCamera'; - - this.zoom = 1; - this.view = null; - - this.left = left; - this.right = right; - this.top = top; - this.bottom = bottom; - - this.near = near; - this.far = far; - - this.updateProjectionMatrix(); - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - this.left = source.left; - this.right = source.right; - this.top = source.top; - this.bottom = source.bottom; - this.near = source.near; - this.far = source.far; - - this.zoom = source.zoom; - this.view = source.view === null ? null : Object.assign( {}, source.view ); - - return this; - - } - - setViewOffset( fullWidth, fullHeight, x, y, width, height ) { - - if ( this.view === null ) { - - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; - - } - - this.view.enabled = true; - this.view.fullWidth = fullWidth; - this.view.fullHeight = fullHeight; - this.view.offsetX = x; - this.view.offsetY = y; - this.view.width = width; - this.view.height = height; - - this.updateProjectionMatrix(); - - } - - clearViewOffset() { - - if ( this.view !== null ) { - - this.view.enabled = false; - - } - - this.updateProjectionMatrix(); - - } - - updateProjectionMatrix() { - - const dx = ( this.right - this.left ) / ( 2 * this.zoom ); - const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); - const cx = ( this.right + this.left ) / 2; - const cy = ( this.top + this.bottom ) / 2; - - let left = cx - dx; - let right = cx + dx; - let top = cy + dy; - let bottom = cy - dy; - - if ( this.view !== null && this.view.enabled ) { - - const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; - const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; - - left += scaleW * this.view.offsetX; - right = left + scaleW * this.view.width; - top -= scaleH * this.view.offsetY; - bottom = top - scaleH * this.view.height; - - } - - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); - - this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.zoom = this.zoom; - data.object.left = this.left; - data.object.right = this.right; - data.object.top = this.top; - data.object.bottom = this.bottom; - data.object.near = this.near; - data.object.far = this.far; - - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); - - return data; - - } - - } - - OrthographicCamera.prototype.isOrthographicCamera = true; - - class RawShaderMaterial extends ShaderMaterial { - - constructor( parameters ) { - - super( parameters ); - - this.type = 'RawShaderMaterial'; - - } - - } - - RawShaderMaterial.prototype.isRawShaderMaterial = true; - - const LOD_MIN = 4; - const LOD_MAX = 8; - const SIZE_MAX = Math.pow( 2, LOD_MAX ); - - // The standard deviations (radians) associated with the extra mips. These are - // chosen to approximate a Trowbridge-Reitz distribution function times the - // geometric shadowing function. These sigma values squared must match the - // variance #defines in cube_uv_reflection_fragment.glsl.js. - const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; - - const TOTAL_LODS = LOD_MAX - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; - - // The maximum length of the blur for loop. Smaller sigmas will use fewer - // samples and exit early, but not recompile the shader. - const MAX_SAMPLES = 20; - - const ENCODINGS = { - [ LinearEncoding ]: 0, - [ sRGBEncoding ]: 1, - [ RGBEEncoding ]: 2, - [ RGBM7Encoding ]: 3, - [ RGBM16Encoding ]: 4, - [ RGBDEncoding ]: 5, - [ GammaEncoding ]: 6 - }; - - const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); - const { _lodPlanes, _sizeLods, _sigmas } = /*@__PURE__*/ _createPlanes(); - const _clearColor = /*@__PURE__*/ new Color(); - let _oldTarget = null; - - // Golden Ratio - const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; - const INV_PHI = 1 / PHI; - - // Vertices of a dodecahedron (except the opposites, which represent the - // same axis), used as axis directions evenly spread on a sphere. - const _axisDirections = [ - /*@__PURE__*/ new Vector3( 1, 1, 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, 1 ), - /*@__PURE__*/ new Vector3( 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), - /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), - /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), - /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), - /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), - /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ]; - - /** - * This class generates a Prefiltered, Mipmapped Radiance Environment Map - * (PMREM) from a cubeMap environment texture. This allows different levels of - * blur to be quickly accessed based on material roughness. It is packed into a - * special CubeUV format that allows us to perform custom interpolation so that - * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap - * chain, it only goes down to the LOD_MIN level (above), and then creates extra - * even more filtered 'mips' at the same LOD_MIN resolution, associated with - * higher roughness levels. In this way we maintain resolution to smoothly - * interpolate diffuse lighting while limiting sampling computation. - * - * Paper: Fast, Accurate Image-Based Lighting - * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view - */ - - class PMREMGenerator { - - constructor( renderer ) { - - this._renderer = renderer; - this._pingPongRenderTarget = null; - - this._blurMaterial = _getBlurShader( MAX_SAMPLES ); - this._equirectShader = null; - this._cubemapShader = null; - - this._compileMaterial( this._blurMaterial ); - - } - - /** - * Generates a PMREM from a supplied Scene, which can be faster than using an - * image if networking bandwidth is low. Optional sigma specifies a blur radius - * in radians to be applied to the scene before PMREM generation. Optional near - * and far planes ensure the scene is rendered in its entirety (the cubeCamera - * is placed at the origin). - */ - fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { - - _oldTarget = this._renderer.getRenderTarget(); - const cubeUVRenderTarget = this._allocateTargets(); - - this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); - if ( sigma > 0 ) { - - this._blur( cubeUVRenderTarget, 0, 0, sigma ); - - } - - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); - - return cubeUVRenderTarget; - - } - - /** - * Generates a PMREM from an equirectangular texture, which can be either LDR - * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512), - * as this matches best with the 256 x 256 cubemap output. - */ - fromEquirectangular( equirectangular ) { - - return this._fromTexture( equirectangular ); - - } - - /** - * Generates a PMREM from an cubemap texture, which can be either LDR - * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256, - * as this matches best with the 256 x 256 cubemap output. - */ - fromCubemap( cubemap ) { - - return this._fromTexture( cubemap ); - - } - - /** - * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileCubemapShader() { - - if ( this._cubemapShader === null ) { - - this._cubemapShader = _getCubemapShader(); - this._compileMaterial( this._cubemapShader ); - - } - - } - - /** - * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during - * your texture's network fetch for increased concurrency. - */ - compileEquirectangularShader() { - - if ( this._equirectShader === null ) { - - this._equirectShader = _getEquirectShader(); - this._compileMaterial( this._equirectShader ); - - } - - } - - /** - * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, - * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on - * one of them will cause any others to also become unusable. - */ - dispose() { - - this._blurMaterial.dispose(); - - if ( this._cubemapShader !== null ) this._cubemapShader.dispose(); - if ( this._equirectShader !== null ) this._equirectShader.dispose(); - - for ( let i = 0; i < _lodPlanes.length; i ++ ) { - - _lodPlanes[ i ].dispose(); - - } - - } - - // private interface - - _cleanup( outputTarget ) { - - this._pingPongRenderTarget.dispose(); - this._renderer.setRenderTarget( _oldTarget ); - outputTarget.scissorTest = false; - _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); - - } - - _fromTexture( texture ) { - - _oldTarget = this._renderer.getRenderTarget(); - const cubeUVRenderTarget = this._allocateTargets( texture ); - this._textureToCubeUV( texture, cubeUVRenderTarget ); - this._applyPMREM( cubeUVRenderTarget ); - this._cleanup( cubeUVRenderTarget ); - - return cubeUVRenderTarget; - - } - - _allocateTargets( texture ) { // warning: null texture is valid - - const params = { - magFilter: NearestFilter, - minFilter: NearestFilter, - generateMipmaps: false, - type: UnsignedByteType, - format: RGBEFormat, - encoding: _isLDR( texture ) ? texture.encoding : RGBEEncoding, - depthBuffer: false - }; - - const cubeUVRenderTarget = _createRenderTarget( params ); - cubeUVRenderTarget.depthBuffer = texture ? false : true; - this._pingPongRenderTarget = _createRenderTarget( params ); - return cubeUVRenderTarget; - - } - - _compileMaterial( material ) { - - const tmpMesh = new Mesh( _lodPlanes[ 0 ], material ); - this._renderer.compile( tmpMesh, _flatCamera ); - - } - - _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { - - const fov = 90; - const aspect = 1; - const cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); - const upSign = [ 1, - 1, 1, 1, 1, 1 ]; - const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; - const renderer = this._renderer; - - const originalAutoClear = renderer.autoClear; - const outputEncoding = renderer.outputEncoding; - const toneMapping = renderer.toneMapping; - renderer.getClearColor( _clearColor ); - - renderer.toneMapping = NoToneMapping; - renderer.outputEncoding = LinearEncoding; - renderer.autoClear = false; - - const backgroundMaterial = new MeshBasicMaterial( { - name: 'PMREM.Background', - side: BackSide, - depthWrite: false, - depthTest: false, - } ); - - const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); - - let useSolidColor = false; - const background = scene.background; - - if ( background ) { - - if ( background.isColor ) { - - backgroundMaterial.color.copy( background ); - scene.background = null; - useSolidColor = true; - - } - - } else { - - backgroundMaterial.color.copy( _clearColor ); - useSolidColor = true; - - } - - for ( let i = 0; i < 6; i ++ ) { - - const col = i % 3; - if ( col == 0 ) { - - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); - - } else if ( col == 1 ) { - - cubeCamera.up.set( 0, 0, upSign[ i ] ); - cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); - - } else { - - cubeCamera.up.set( 0, upSign[ i ], 0 ); - cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); - - } - - _setViewport( cubeUVRenderTarget, - col * SIZE_MAX, i > 2 ? SIZE_MAX : 0, SIZE_MAX, SIZE_MAX ); - renderer.setRenderTarget( cubeUVRenderTarget ); - - if ( useSolidColor ) { - - renderer.render( backgroundBox, cubeCamera ); - - } - - renderer.render( scene, cubeCamera ); - - } - - backgroundBox.geometry.dispose(); - backgroundBox.material.dispose(); - - renderer.toneMapping = toneMapping; - renderer.outputEncoding = outputEncoding; - renderer.autoClear = originalAutoClear; - scene.background = background; - - } - - _textureToCubeUV( texture, cubeUVRenderTarget ) { - - const renderer = this._renderer; - - if ( texture.isCubeTexture ) { - - if ( this._cubemapShader == null ) { - - this._cubemapShader = _getCubemapShader(); - - } - - } else { - - if ( this._equirectShader == null ) { - - this._equirectShader = _getEquirectShader(); - - } - - } - - const material = texture.isCubeTexture ? this._cubemapShader : this._equirectShader; - const mesh = new Mesh( _lodPlanes[ 0 ], material ); - - const uniforms = material.uniforms; - - uniforms[ 'envMap' ].value = texture; - - if ( ! texture.isCubeTexture ) { - - uniforms[ 'texelSize' ].value.set( 1.0 / texture.image.width, 1.0 / texture.image.height ); - - } - - uniforms[ 'inputEncoding' ].value = ENCODINGS[ texture.encoding ]; - uniforms[ 'outputEncoding' ].value = ENCODINGS[ cubeUVRenderTarget.texture.encoding ]; - - _setViewport( cubeUVRenderTarget, 0, 0, 3 * SIZE_MAX, 2 * SIZE_MAX ); - - renderer.setRenderTarget( cubeUVRenderTarget ); - renderer.render( mesh, _flatCamera ); - - } - - _applyPMREM( cubeUVRenderTarget ) { - - const renderer = this._renderer; - const autoClear = renderer.autoClear; - renderer.autoClear = false; - - for ( let i = 1; i < TOTAL_LODS; i ++ ) { - - const sigma = Math.sqrt( _sigmas[ i ] * _sigmas[ i ] - _sigmas[ i - 1 ] * _sigmas[ i - 1 ] ); - - const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ]; - - this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); - - } - - renderer.autoClear = autoClear; - - } - - /** - * This is a two-pass Gaussian blur for a cubemap. Normally this is done - * vertically and horizontally, but this breaks down on a cube. Here we apply - * the blur latitudinally (around the poles), and then longitudinally (towards - * the poles) to approximate the orthogonally-separable blur. It is least - * accurate at the poles, but still does a decent job. - */ - _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { - - const pingPongRenderTarget = this._pingPongRenderTarget; - - this._halfBlur( - cubeUVRenderTarget, - pingPongRenderTarget, - lodIn, - lodOut, - sigma, - 'latitudinal', - poleAxis ); - - this._halfBlur( - pingPongRenderTarget, - cubeUVRenderTarget, - lodOut, - lodOut, - sigma, - 'longitudinal', - poleAxis ); - - } - - _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { - - const renderer = this._renderer; - const blurMaterial = this._blurMaterial; - - if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { - - console.error( - 'blur direction must be either latitudinal or longitudinal!' ); - - } - - // Number of standard deviations at which to cut off the discrete approximation. - const STANDARD_DEVIATIONS = 3; - - const blurMesh = new Mesh( _lodPlanes[ lodOut ], blurMaterial ); - const blurUniforms = blurMaterial.uniforms; - - const pixels = _sizeLods[ lodIn ] - 1; - const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); - const sigmaPixels = sigmaRadians / radiansPerPixel; - const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; - - if ( samples > MAX_SAMPLES ) { - - console.warn( `sigmaRadians, ${ - sigmaRadians}, is too large and will clip, as it requested ${ - samples} samples when the maximum is set to ${MAX_SAMPLES}` ); - - } - - const weights = []; - let sum = 0; - - for ( let i = 0; i < MAX_SAMPLES; ++ i ) { - - const x = i / sigmaPixels; - const weight = Math.exp( - x * x / 2 ); - weights.push( weight ); - - if ( i == 0 ) { - - sum += weight; - - } else if ( i < samples ) { - - sum += 2 * weight; - - } - - } - - for ( let i = 0; i < weights.length; i ++ ) { - - weights[ i ] = weights[ i ] / sum; - - } - - blurUniforms[ 'envMap' ].value = targetIn.texture; - blurUniforms[ 'samples' ].value = samples; - blurUniforms[ 'weights' ].value = weights; - blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal'; - - if ( poleAxis ) { - - blurUniforms[ 'poleAxis' ].value = poleAxis; - - } - - blurUniforms[ 'dTheta' ].value = radiansPerPixel; - blurUniforms[ 'mipInt' ].value = LOD_MAX - lodIn; - blurUniforms[ 'inputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ]; - blurUniforms[ 'outputEncoding' ].value = ENCODINGS[ targetIn.texture.encoding ]; - - const outputSize = _sizeLods[ lodOut ]; - const x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize ); - const y = ( lodOut === 0 ? 0 : 2 * SIZE_MAX ) + 2 * outputSize * ( lodOut > LOD_MAX - LOD_MIN ? lodOut - LOD_MAX + LOD_MIN : 0 ); - - _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); - renderer.setRenderTarget( targetOut ); - renderer.render( blurMesh, _flatCamera ); - - } - - } - - function _isLDR( texture ) { - - if ( texture === undefined || texture.type !== UnsignedByteType ) return false; - - return texture.encoding === LinearEncoding || texture.encoding === sRGBEncoding || texture.encoding === GammaEncoding; - - } - - function _createPlanes() { - - const _lodPlanes = []; - const _sizeLods = []; - const _sigmas = []; - - let lod = LOD_MAX; - - for ( let i = 0; i < TOTAL_LODS; i ++ ) { - - const sizeLod = Math.pow( 2, lod ); - _sizeLods.push( sizeLod ); - let sigma = 1.0 / sizeLod; - - if ( i > LOD_MAX - LOD_MIN ) { - - sigma = EXTRA_LOD_SIGMA[ i - LOD_MAX + LOD_MIN - 1 ]; - - } else if ( i == 0 ) { - - sigma = 0; - - } - - _sigmas.push( sigma ); - - const texelSize = 1.0 / ( sizeLod - 1 ); - const min = - texelSize / 2; - const max = 1 + texelSize / 2; - const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; - - const cubeFaces = 6; - const vertices = 6; - const positionSize = 3; - const uvSize = 2; - const faceIndexSize = 1; - - const position = new Float32Array( positionSize * vertices * cubeFaces ); - const uv = new Float32Array( uvSize * vertices * cubeFaces ); - const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); - - for ( let face = 0; face < cubeFaces; face ++ ) { - - const x = ( face % 3 ) * 2 / 3 - 1; - const y = face > 2 ? 0 : - 1; - const coordinates = [ - x, y, 0, - x + 2 / 3, y, 0, - x + 2 / 3, y + 1, 0, - x, y, 0, - x + 2 / 3, y + 1, 0, - x, y + 1, 0 - ]; - position.set( coordinates, positionSize * vertices * face ); - uv.set( uv1, uvSize * vertices * face ); - const fill = [ face, face, face, face, face, face ]; - faceIndex.set( fill, faceIndexSize * vertices * face ); - - } - - const planes = new BufferGeometry(); - planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); - planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); - planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); - _lodPlanes.push( planes ); - - if ( lod > LOD_MIN ) { - - lod --; - - } - - } - - return { _lodPlanes, _sizeLods, _sigmas }; - - } - - function _createRenderTarget( params ) { - - const cubeUVRenderTarget = new WebGLRenderTarget( 3 * SIZE_MAX, 3 * SIZE_MAX, params ); - cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; - cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; - cubeUVRenderTarget.scissorTest = true; - return cubeUVRenderTarget; - - } - - function _setViewport( target, x, y, width, height ) { - - target.viewport.set( x, y, width, height ); - target.scissor.set( x, y, width, height ); - - } - - function _getBlurShader( maxSamples ) { - - const weights = new Float32Array( maxSamples ); - const poleAxis = new Vector3( 0, 1, 0 ); - const shaderMaterial = new RawShaderMaterial( { - - name: 'SphericalGaussianBlur', - - defines: { 'n': maxSamples }, - - uniforms: { - 'envMap': { value: null }, - 'samples': { value: 1 }, - 'weights': { value: weights }, - 'latitudinal': { value: false }, - 'dTheta': { value: 0 }, - 'mipInt': { value: 0 }, - 'poleAxis': { value: poleAxis }, - 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, - 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform sampler2D envMap; - uniform int samples; - uniform float weights[ n ]; - uniform bool latitudinal; - uniform float dTheta; - uniform float mipInt; - uniform vec3 poleAxis; - - ${ _getEncodings() } - - #define ENVMAP_TYPE_CUBE_UV - #include - - vec3 getSample( float theta, vec3 axis ) { - - float cosTheta = cos( theta ); - // Rodrigues' axis-angle rotation - vec3 sampleDirection = vOutputDirection * cosTheta - + cross( axis, vOutputDirection ) * sin( theta ) - + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); - - return bilinearCubeUV( envMap, sampleDirection, mipInt ); - - } - - void main() { - - vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); - - if ( all( equal( axis, vec3( 0.0 ) ) ) ) { - - axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); - - } - - axis = normalize( axis ); - - gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); - - for ( int i = 1; i < n; i++ ) { - - if ( i >= samples ) { - - break; - - } - - float theta = dTheta * float( i ); - gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); - gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); - - } - - gl_FragColor = linearToOutputTexel( gl_FragColor ); - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - - return shaderMaterial; - - } - - function _getEquirectShader() { - - const texelSize = new Vector2( 1, 1 ); - const shaderMaterial = new RawShaderMaterial( { - - name: 'EquirectangularToCubeUV', - - uniforms: { - 'envMap': { value: null }, - 'texelSize': { value: texelSize }, - 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, - 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform sampler2D envMap; - uniform vec2 texelSize; - - ${ _getEncodings() } - - #include - - void main() { - - gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - - vec3 outputDirection = normalize( vOutputDirection ); - vec2 uv = equirectUv( outputDirection ); - - vec2 f = fract( uv / texelSize - 0.5 ); - uv -= f * texelSize; - vec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb; - uv.x += texelSize.x; - vec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb; - uv.y += texelSize.y; - vec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb; - uv.x -= texelSize.x; - vec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb; - - vec3 tm = mix( tl, tr, f.x ); - vec3 bm = mix( bl, br, f.x ); - gl_FragColor.rgb = mix( tm, bm, f.y ); - - gl_FragColor = linearToOutputTexel( gl_FragColor ); - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - - return shaderMaterial; - - } - - function _getCubemapShader() { - - const shaderMaterial = new RawShaderMaterial( { - - name: 'CubemapToCubeUV', - - uniforms: { - 'envMap': { value: null }, - 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, - 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } - }, - - vertexShader: _getCommonVertexShader(), - - fragmentShader: /* glsl */` - - precision mediump float; - precision mediump int; - - varying vec3 vOutputDirection; - - uniform samplerCube envMap; - - ${ _getEncodings() } - - void main() { - - gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); - gl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb; - gl_FragColor = linearToOutputTexel( gl_FragColor ); - - } - `, - - blending: NoBlending, - depthTest: false, - depthWrite: false - - } ); - - return shaderMaterial; - - } - - function _getCommonVertexShader() { - - return /* glsl */` - - precision mediump float; - precision mediump int; - - attribute vec3 position; - attribute vec2 uv; - attribute float faceIndex; - - varying vec3 vOutputDirection; - - // RH coordinate system; PMREM face-indexing convention - vec3 getDirection( vec2 uv, float face ) { - - uv = 2.0 * uv - 1.0; - - vec3 direction = vec3( uv, 1.0 ); - - if ( face == 0.0 ) { - - direction = direction.zyx; // ( 1, v, u ) pos x - - } else if ( face == 1.0 ) { - - direction = direction.xzy; - direction.xz *= -1.0; // ( -u, 1, -v ) pos y - - } else if ( face == 2.0 ) { - - direction.x *= -1.0; // ( -u, v, 1 ) pos z - - } else if ( face == 3.0 ) { - - direction = direction.zyx; - direction.xz *= -1.0; // ( -1, v, -u ) neg x - - } else if ( face == 4.0 ) { - - direction = direction.xzy; - direction.xy *= -1.0; // ( -u, -1, v ) neg y - - } else if ( face == 5.0 ) { - - direction.z *= -1.0; // ( u, v, -1 ) neg z - - } - - return direction; - - } - - void main() { - - vOutputDirection = getDirection( uv, faceIndex ); - gl_Position = vec4( position, 1.0 ); - - } - `; - - } - - function _getEncodings() { - - return /* glsl */` - - uniform int inputEncoding; - uniform int outputEncoding; - - #include - - vec4 inputTexelToLinear( vec4 value ) { - - if ( inputEncoding == 0 ) { - - return value; - - } else if ( inputEncoding == 1 ) { - - return sRGBToLinear( value ); - - } else if ( inputEncoding == 2 ) { - - return RGBEToLinear( value ); - - } else if ( inputEncoding == 3 ) { - - return RGBMToLinear( value, 7.0 ); - - } else if ( inputEncoding == 4 ) { - - return RGBMToLinear( value, 16.0 ); - - } else if ( inputEncoding == 5 ) { - - return RGBDToLinear( value, 256.0 ); - - } else { - - return GammaToLinear( value, 2.2 ); - - } - - } - - vec4 linearToOutputTexel( vec4 value ) { - - if ( outputEncoding == 0 ) { - - return value; - - } else if ( outputEncoding == 1 ) { - - return LinearTosRGB( value ); - - } else if ( outputEncoding == 2 ) { - - return LinearToRGBE( value ); - - } else if ( outputEncoding == 3 ) { - - return LinearToRGBM( value, 7.0 ); - - } else if ( outputEncoding == 4 ) { - - return LinearToRGBM( value, 16.0 ); - - } else if ( outputEncoding == 5 ) { - - return LinearToRGBD( value, 256.0 ); - - } else { - - return LinearToGamma( value, 2.2 ); - - } - - } - - vec4 envMapTexelToLinear( vec4 color ) { - - return inputTexelToLinear( color ); - - } - `; - - } - - function WebGLCubeUVMaps( renderer ) { - - let cubeUVmaps = new WeakMap(); - - let pmremGenerator = null; - - function get( texture ) { - - if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) { - - const mapping = texture.mapping; - - const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ); - const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); - - if ( isEquirectMap || isCubeMap ) { - - // equirect/cube map to cubeUV conversion - - if ( cubeUVmaps.has( texture ) ) { - - return cubeUVmaps.get( texture ).texture; - - } else { - - const image = texture.image; - - if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) { - - const currentRenderTarget = renderer.getRenderTarget(); - - if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); - - const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture ); - cubeUVmaps.set( texture, renderTarget ); - - renderer.setRenderTarget( currentRenderTarget ); - - texture.addEventListener( 'dispose', onTextureDispose ); - - return renderTarget.texture; - - } else { - - // image not yet ready. try the conversion next frame - - return null; - - } - - } - - } - - } - - return texture; - - } - - function isCubeTextureComplete( image ) { - - let count = 0; - const length = 6; - - for ( let i = 0; i < length; i ++ ) { - - if ( image[ i ] !== undefined ) count ++; - - } - - return count === length; - - - } - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - const cubemapUV = cubeUVmaps.get( texture ); - - if ( cubemapUV !== undefined ) { - - cubeUVmaps.delete( texture ); - cubemapUV.dispose(); - - } - - } - - function dispose() { - - cubeUVmaps = new WeakMap(); - - if ( pmremGenerator !== null ) { - - pmremGenerator.dispose(); - pmremGenerator = null; - - } - - } - - return { - get: get, - dispose: dispose - }; - - } - - function WebGLExtensions( gl ) { - - const extensions = {}; - - function getExtension( name ) { - - if ( extensions[ name ] !== undefined ) { - - return extensions[ name ]; - - } - - let extension; - - switch ( name ) { - - case 'WEBGL_depth_texture': - extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); - break; - - case 'EXT_texture_filter_anisotropic': - extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); - break; - - case 'WEBGL_compressed_texture_s3tc': - extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); - break; - - case 'WEBGL_compressed_texture_pvrtc': - extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); - break; - - default: - extension = gl.getExtension( name ); - - } - - extensions[ name ] = extension; - - return extension; - - } - - return { - - has: function ( name ) { - - return getExtension( name ) !== null; - - }, - - init: function ( capabilities ) { - - if ( capabilities.isWebGL2 ) { - - getExtension( 'EXT_color_buffer_float' ); - - } else { - - getExtension( 'WEBGL_depth_texture' ); - getExtension( 'OES_texture_float' ); - getExtension( 'OES_texture_half_float' ); - getExtension( 'OES_texture_half_float_linear' ); - getExtension( 'OES_standard_derivatives' ); - getExtension( 'OES_element_index_uint' ); - getExtension( 'OES_vertex_array_object' ); - getExtension( 'ANGLE_instanced_arrays' ); - - } - - getExtension( 'OES_texture_float_linear' ); - getExtension( 'EXT_color_buffer_half_float' ); - - }, - - get: function ( name ) { - - const extension = getExtension( name ); - - if ( extension === null ) { - - console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - - } - - return extension; - - } - - }; - - } - - function WebGLGeometries( gl, attributes, info, bindingStates ) { - - const geometries = {}; - const wireframeAttributes = new WeakMap(); - - function onGeometryDispose( event ) { - - const geometry = event.target; - - if ( geometry.index !== null ) { - - attributes.remove( geometry.index ); - - } - - for ( const name in geometry.attributes ) { - - attributes.remove( geometry.attributes[ name ] ); - - } - - geometry.removeEventListener( 'dispose', onGeometryDispose ); - - delete geometries[ geometry.id ]; - - const attribute = wireframeAttributes.get( geometry ); - - if ( attribute ) { - - attributes.remove( attribute ); - wireframeAttributes.delete( geometry ); - - } - - bindingStates.releaseStatesOfGeometry( geometry ); - - if ( geometry.isInstancedBufferGeometry === true ) { - - delete geometry._maxInstanceCount; - - } - - // - - info.memory.geometries --; - - } - - function get( object, geometry ) { - - if ( geometries[ geometry.id ] === true ) return geometry; - - geometry.addEventListener( 'dispose', onGeometryDispose ); - - geometries[ geometry.id ] = true; - - info.memory.geometries ++; - - return geometry; - - } - - function update( geometry ) { - - const geometryAttributes = geometry.attributes; - - // Updating index buffer in VAO now. See WebGLBindingStates. - - for ( const name in geometryAttributes ) { - - attributes.update( geometryAttributes[ name ], 34962 ); - - } - - // morph targets - - const morphAttributes = geometry.morphAttributes; - - for ( const name in morphAttributes ) { - - const array = morphAttributes[ name ]; - - for ( let i = 0, l = array.length; i < l; i ++ ) { - - attributes.update( array[ i ], 34962 ); - - } - - } - - } - - function updateWireframeAttribute( geometry ) { - - const indices = []; - - const geometryIndex = geometry.index; - const geometryPosition = geometry.attributes.position; - let version = 0; - - if ( geometryIndex !== null ) { - - const array = geometryIndex.array; - version = geometryIndex.version; - - for ( let i = 0, l = array.length; i < l; i += 3 ) { - - const a = array[ i + 0 ]; - const b = array[ i + 1 ]; - const c = array[ i + 2 ]; - - indices.push( a, b, b, c, c, a ); - - } - - } else { - - const array = geometryPosition.array; - version = geometryPosition.version; - - for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { - - const a = i + 0; - const b = i + 1; - const c = i + 2; - - indices.push( a, b, b, c, c, a ); - - } - - } - - const attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); - attribute.version = version; - - // Updating index buffer in VAO now. See WebGLBindingStates - - // - - const previousAttribute = wireframeAttributes.get( geometry ); - - if ( previousAttribute ) attributes.remove( previousAttribute ); - - // - - wireframeAttributes.set( geometry, attribute ); - - } - - function getWireframeAttribute( geometry ) { - - const currentAttribute = wireframeAttributes.get( geometry ); - - if ( currentAttribute ) { - - const geometryIndex = geometry.index; - - if ( geometryIndex !== null ) { - - // if the attribute is obsolete, create a new one - - if ( currentAttribute.version < geometryIndex.version ) { - - updateWireframeAttribute( geometry ); - - } - - } - - } else { - - updateWireframeAttribute( geometry ); - - } - - return wireframeAttributes.get( geometry ); - - } - - return { - - get: get, - update: update, - - getWireframeAttribute: getWireframeAttribute - - }; - - } - - function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - let mode; - - function setMode( value ) { - - mode = value; - - } - - let type, bytesPerElement; - - function setIndex( value ) { - - type = value.type; - bytesPerElement = value.bytesPerElement; - - } - - function render( start, count ) { - - gl.drawElements( mode, count, type, start * bytesPerElement ); - - info.update( count, mode, 1 ); - - } - - function renderInstances( start, count, primcount ) { - - if ( primcount === 0 ) return; - - let extension, methodName; - - if ( isWebGL2 ) { - - extension = gl; - methodName = 'drawElementsInstanced'; - - } else { - - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawElementsInstancedANGLE'; - - if ( extension === null ) { - - console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; - - } - - } - - extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); - - info.update( count, mode, primcount ); - - } - - // - - this.setMode = setMode; - this.setIndex = setIndex; - this.render = render; - this.renderInstances = renderInstances; - - } - - function WebGLInfo( gl ) { - - const memory = { - geometries: 0, - textures: 0 - }; - - const render = { - frame: 0, - calls: 0, - triangles: 0, - points: 0, - lines: 0 - }; - - function update( count, mode, instanceCount ) { - - render.calls ++; - - switch ( mode ) { - - case 4: - render.triangles += instanceCount * ( count / 3 ); - break; - - case 1: - render.lines += instanceCount * ( count / 2 ); - break; - - case 3: - render.lines += instanceCount * ( count - 1 ); - break; - - case 2: - render.lines += instanceCount * count; - break; - - case 0: - render.points += instanceCount * count; - break; - - default: - console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode ); - break; - - } - - } - - function reset() { - - render.frame ++; - render.calls = 0; - render.triangles = 0; - render.points = 0; - render.lines = 0; - - } - - return { - memory: memory, - render: render, - programs: null, - autoReset: true, - reset: reset, - update: update - }; - - } - - function numericalSort( a, b ) { - - return a[ 0 ] - b[ 0 ]; - - } - - function absNumericalSort( a, b ) { - - return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); - - } - - function WebGLMorphtargets( gl ) { - - const influencesList = {}; - const morphInfluences = new Float32Array( 8 ); - - const workInfluences = []; - - for ( let i = 0; i < 8; i ++ ) { - - workInfluences[ i ] = [ i, 0 ]; - - } - - function update( object, geometry, material, program ) { - - const objectInfluences = object.morphTargetInfluences; - - // When object doesn't have morph target influences defined, we treat it as a 0-length array - // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences - - const length = objectInfluences === undefined ? 0 : objectInfluences.length; - - let influences = influencesList[ geometry.id ]; - - if ( influences === undefined || influences.length !== length ) { - - // initialise list - - influences = []; - - for ( let i = 0; i < length; i ++ ) { - - influences[ i ] = [ i, 0 ]; - - } - - influencesList[ geometry.id ] = influences; - - } - - // Collect influences - - for ( let i = 0; i < length; i ++ ) { - - const influence = influences[ i ]; - - influence[ 0 ] = i; - influence[ 1 ] = objectInfluences[ i ]; - - } - - influences.sort( absNumericalSort ); - - for ( let i = 0; i < 8; i ++ ) { - - if ( i < length && influences[ i ][ 1 ] ) { - - workInfluences[ i ][ 0 ] = influences[ i ][ 0 ]; - workInfluences[ i ][ 1 ] = influences[ i ][ 1 ]; - - } else { - - workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER; - workInfluences[ i ][ 1 ] = 0; - - } - - } - - workInfluences.sort( numericalSort ); - - const morphTargets = geometry.morphAttributes.position; - const morphNormals = geometry.morphAttributes.normal; - - let morphInfluencesSum = 0; - - for ( let i = 0; i < 8; i ++ ) { - - const influence = workInfluences[ i ]; - const index = influence[ 0 ]; - const value = influence[ 1 ]; - - if ( index !== Number.MAX_SAFE_INTEGER && value ) { - - if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) { - - geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] ); - - } - - if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) { - - geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] ); - - } - - morphInfluences[ i ] = value; - morphInfluencesSum += value; - - } else { - - if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) { - - geometry.deleteAttribute( 'morphTarget' + i ); - - } - - if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) { - - geometry.deleteAttribute( 'morphNormal' + i ); - - } - - morphInfluences[ i ] = 0; - - } - - } - - // GLSL shader uses formula baseinfluence * base + sum(target * influence) - // This allows us to switch between absolute morphs and relative morphs without changing shader code - // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence) - const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; - - program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); - program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); - - } - - return { - - update: update - - }; - - } - - function WebGLObjects( gl, geometries, attributes, info ) { - - let updateMap = new WeakMap(); - - function update( object ) { - - const frame = info.render.frame; - - const geometry = object.geometry; - const buffergeometry = geometries.get( object, geometry ); - - // Update once per frame - - if ( updateMap.get( buffergeometry ) !== frame ) { - - geometries.update( buffergeometry ); - - updateMap.set( buffergeometry, frame ); - - } - - if ( object.isInstancedMesh ) { - - if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) { - - object.addEventListener( 'dispose', onInstancedMeshDispose ); - - } - - attributes.update( object.instanceMatrix, 34962 ); - - if ( object.instanceColor !== null ) { - - attributes.update( object.instanceColor, 34962 ); - - } - - } - - return buffergeometry; - - } - - function dispose() { - - updateMap = new WeakMap(); - - } - - function onInstancedMeshDispose( event ) { - - const instancedMesh = event.target; - - instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose ); - - attributes.remove( instancedMesh.instanceMatrix ); - - if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor ); - - } - - return { - - update: update, - dispose: dispose - - }; - - } - - class DataTexture2DArray extends Texture { - - constructor( data = null, width = 1, height = 1, depth = 1 ) { - - super( null ); - - this.image = { data, width, height, depth }; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; - - this.wrapR = ClampToEdgeWrapping; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - this.needsUpdate = true; - - } - - } - - DataTexture2DArray.prototype.isDataTexture2DArray = true; - - class DataTexture3D extends Texture { - - constructor( data = null, width = 1, height = 1, depth = 1 ) { - - // We're going to add .setXXX() methods for setting properties later. - // Users can still set in DataTexture3D directly. - // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); - // texture.anisotropy = 16; - // - // See #14839 - - super( null ); - - this.image = { data, width, height, depth }; - - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; - - this.wrapR = ClampToEdgeWrapping; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - this.needsUpdate = true; - - } - - } - - DataTexture3D.prototype.isDataTexture3D = true; - - /** - * Uniforms of a program. - * Those form a tree structure with a special top-level container for the root, - * which you get by calling 'new WebGLUniforms( gl, program )'. - * - * - * Properties of inner nodes including the top-level container: - * - * .seq - array of nested uniforms - * .map - nested uniforms by name - * - * - * Methods of all nodes except the top-level container: - * - * .setValue( gl, value, [textures] ) - * - * uploads a uniform value(s) - * the 'textures' parameter is needed for sampler uniforms - * - * - * Static methods of the top-level container (textures factorizations): - * - * .upload( gl, seq, values, textures ) - * - * sets uniforms in 'seq' to 'values[id].value' - * - * .seqWithValue( seq, values ) : filteredSeq - * - * filters 'seq' entries with corresponding entry in values - * - * - * Methods of the top-level container (textures factorizations): - * - * .setValue( gl, name, value, textures ) - * - * sets uniform with name 'name' to 'value' - * - * .setOptional( gl, obj, prop ) - * - * like .set for an optional property of the object - * - */ - - const emptyTexture = new Texture(); - const emptyTexture2dArray = new DataTexture2DArray(); - const emptyTexture3d = new DataTexture3D(); - const emptyCubeTexture = new CubeTexture(); - - // --- Utilities --- - - // Array Caches (provide typed arrays for temporary by size) - - const arrayCacheF32 = []; - const arrayCacheI32 = []; - - // Float32Array caches used for uploading Matrix uniforms - - const mat4array = new Float32Array( 16 ); - const mat3array = new Float32Array( 9 ); - const mat2array = new Float32Array( 4 ); - - // Flattening for arrays of vectors and matrices - - function flatten( array, nBlocks, blockSize ) { - - const firstElem = array[ 0 ]; - - if ( firstElem <= 0 || firstElem > 0 ) return array; - // unoptimized: ! isNaN( firstElem ) - // see http://jacksondunstan.com/articles/983 - - const n = nBlocks * blockSize; - let r = arrayCacheF32[ n ]; - - if ( r === undefined ) { - - r = new Float32Array( n ); - arrayCacheF32[ n ] = r; - - } - - if ( nBlocks !== 0 ) { - - firstElem.toArray( r, 0 ); - - for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) { - - offset += blockSize; - array[ i ].toArray( r, offset ); - - } - - } - - return r; - - } - - function arraysEqual( a, b ) { - - if ( a.length !== b.length ) return false; - - for ( let i = 0, l = a.length; i < l; i ++ ) { - - if ( a[ i ] !== b[ i ] ) return false; - - } - - return true; - - } - - function copyArray( a, b ) { - - for ( let i = 0, l = b.length; i < l; i ++ ) { - - a[ i ] = b[ i ]; - - } - - } - - // Texture unit allocation - - function allocTexUnits( textures, n ) { - - let r = arrayCacheI32[ n ]; - - if ( r === undefined ) { - - r = new Int32Array( n ); - arrayCacheI32[ n ] = r; - - } - - for ( let i = 0; i !== n; ++ i ) { - - r[ i ] = textures.allocateTextureUnit(); - - } - - return r; - - } - - // --- Setters --- - - // Note: Defining these methods externally, because they come in a bunch - // and this way their names minify. - - // Single scalar - - function setValueV1f( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1f( this.addr, v ); - - cache[ 0 ] = v; - - } - - // Single float vector (from flat array or THREE.VectorN) - - function setValueV2f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - - gl.uniform2f( this.addr, v.x, v.y ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2fv( this.addr, v ); - - copyArray( cache, v ); - - } - - } - - function setValueV3f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - - gl.uniform3f( this.addr, v.x, v.y, v.z ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - - } - - } else if ( v.r !== undefined ) { - - if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { - - gl.uniform3f( this.addr, v.r, v.g, v.b ); - - cache[ 0 ] = v.r; - cache[ 1 ] = v.g; - cache[ 2 ] = v.b; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3fv( this.addr, v ); - - copyArray( cache, v ); - - } - - } - - function setValueV4f( gl, v ) { - - const cache = this.cache; - - if ( v.x !== undefined ) { - - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - - gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); - - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; - - } - - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4fv( this.addr, v ); - - copyArray( cache, v ); - - } - - } - - // Single matrix (from flat array or THREE.MatrixN) - - function setValueM2( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix2fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat2array.set( elements ); - - gl.uniformMatrix2fv( this.addr, false, mat2array ); - - copyArray( cache, elements ); - - } - - } - - function setValueM3( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix3fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat3array.set( elements ); - - gl.uniformMatrix3fv( this.addr, false, mat3array ); - - copyArray( cache, elements ); - - } - - } - - function setValueM4( gl, v ) { - - const cache = this.cache; - const elements = v.elements; - - if ( elements === undefined ) { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniformMatrix4fv( this.addr, false, v ); - - copyArray( cache, v ); - - } else { - - if ( arraysEqual( cache, elements ) ) return; - - mat4array.set( elements ); - - gl.uniformMatrix4fv( this.addr, false, mat4array ); - - copyArray( cache, elements ); - - } - - } - - // Single integer / boolean - - function setValueV1i( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1i( this.addr, v ); - - cache[ 0 ] = v; - - } - - // Single integer / boolean vector (from flat array) - - function setValueV2i( gl, v ) { - - const cache = this.cache; - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2iv( this.addr, v ); - - copyArray( cache, v ); - - } - - function setValueV3i( gl, v ) { - - const cache = this.cache; - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3iv( this.addr, v ); - - copyArray( cache, v ); - - } - - function setValueV4i( gl, v ) { - - const cache = this.cache; - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4iv( this.addr, v ); - - copyArray( cache, v ); - - } - - // Single unsigned integer - - function setValueV1ui( gl, v ) { - - const cache = this.cache; - - if ( cache[ 0 ] === v ) return; - - gl.uniform1ui( this.addr, v ); - - cache[ 0 ] = v; - - } - - // Single unsigned integer vector (from flat array) - - function setValueV2ui( gl, v ) { - - const cache = this.cache; - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform2uiv( this.addr, v ); - - copyArray( cache, v ); - - } - - function setValueV3ui( gl, v ) { - - const cache = this.cache; - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3uiv( this.addr, v ); - - copyArray( cache, v ); - - } - - function setValueV4ui( gl, v ) { - - const cache = this.cache; - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform4uiv( this.addr, v ); - - copyArray( cache, v ); - - } - - - // Single texture (2D / Cube) - - function setValueT1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.safeSetTexture2D( v || emptyTexture, unit ); - - } - - function setValueT3D1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.setTexture3D( v || emptyTexture3d, unit ); - - } - - function setValueT6( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.safeSetTextureCube( v || emptyCubeTexture, unit ); - - } - - function setValueT2DArray1( gl, v, textures ) { - - const cache = this.cache; - const unit = textures.allocateTextureUnit(); - - if ( cache[ 0 ] !== unit ) { - - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; - - } - - textures.setTexture2DArray( v || emptyTexture2dArray, unit ); - - } - - // Helper to pick the right setter for the singular case - - function getSingularSetter( type ) { - - switch ( type ) { - - case 0x1406: return setValueV1f; // FLOAT - case 0x8b50: return setValueV2f; // _VEC2 - case 0x8b51: return setValueV3f; // _VEC3 - case 0x8b52: return setValueV4f; // _VEC4 - - case 0x8b5a: return setValueM2; // _MAT2 - case 0x8b5b: return setValueM3; // _MAT3 - case 0x8b5c: return setValueM4; // _MAT4 - - case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL - case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2 - case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3 - case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4 - - case 0x1405: return setValueV1ui; // UINT - case 0x8dc6: return setValueV2ui; // _VEC2 - case 0x8dc7: return setValueV3ui; // _VEC3 - case 0x8dc8: return setValueV4ui; // _VEC4 - - case 0x8b5e: // SAMPLER_2D - case 0x8d66: // SAMPLER_EXTERNAL_OES - case 0x8dca: // INT_SAMPLER_2D - case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D - case 0x8b62: // SAMPLER_2D_SHADOW - return setValueT1; - - case 0x8b5f: // SAMPLER_3D - case 0x8dcb: // INT_SAMPLER_3D - case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D - return setValueT3D1; - - case 0x8b60: // SAMPLER_CUBE - case 0x8dcc: // INT_SAMPLER_CUBE - case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE - case 0x8dc5: // SAMPLER_CUBE_SHADOW - return setValueT6; - - case 0x8dc1: // SAMPLER_2D_ARRAY - case 0x8dcf: // INT_SAMPLER_2D_ARRAY - case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY - case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW - return setValueT2DArray1; - - } - - } - - - // Array of scalars - - function setValueV1fArray( gl, v ) { - - gl.uniform1fv( this.addr, v ); - - } - - // Array of vectors (from flat array or array of THREE.VectorN) - - function setValueV2fArray( gl, v ) { - - const data = flatten( v, this.size, 2 ); - - gl.uniform2fv( this.addr, data ); - - } - - function setValueV3fArray( gl, v ) { - - const data = flatten( v, this.size, 3 ); - - gl.uniform3fv( this.addr, data ); - - } - - function setValueV4fArray( gl, v ) { - - const data = flatten( v, this.size, 4 ); - - gl.uniform4fv( this.addr, data ); - - } - - // Array of matrices (from flat array or array of THREE.MatrixN) - - function setValueM2Array( gl, v ) { - - const data = flatten( v, this.size, 4 ); - - gl.uniformMatrix2fv( this.addr, false, data ); - - } - - function setValueM3Array( gl, v ) { - - const data = flatten( v, this.size, 9 ); - - gl.uniformMatrix3fv( this.addr, false, data ); - - } - - function setValueM4Array( gl, v ) { - - const data = flatten( v, this.size, 16 ); - - gl.uniformMatrix4fv( this.addr, false, data ); - - } - - // Array of integer / boolean - - function setValueV1iArray( gl, v ) { - - gl.uniform1iv( this.addr, v ); - - } - - // Array of integer / boolean vectors (from flat array) - - function setValueV2iArray( gl, v ) { - - gl.uniform2iv( this.addr, v ); - - } - - function setValueV3iArray( gl, v ) { - - gl.uniform3iv( this.addr, v ); - - } - - function setValueV4iArray( gl, v ) { - - gl.uniform4iv( this.addr, v ); - - } - - // Array of unsigned integer - - function setValueV1uiArray( gl, v ) { - - gl.uniform1uiv( this.addr, v ); - - } - - // Array of unsigned integer vectors (from flat array) - - function setValueV2uiArray( gl, v ) { - - gl.uniform2uiv( this.addr, v ); - - } - - function setValueV3uiArray( gl, v ) { - - gl.uniform3uiv( this.addr, v ); - - } - - function setValueV4uiArray( gl, v ) { - - gl.uniform4uiv( this.addr, v ); - - } - - - // Array of textures (2D / Cube) - - function setValueT1Array( gl, v, textures ) { - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - gl.uniform1iv( this.addr, units ); - - for ( let i = 0; i !== n; ++ i ) { - - textures.safeSetTexture2D( v[ i ] || emptyTexture, units[ i ] ); - - } - - } - - function setValueT6Array( gl, v, textures ) { - - const n = v.length; - - const units = allocTexUnits( textures, n ); - - gl.uniform1iv( this.addr, units ); - - for ( let i = 0; i !== n; ++ i ) { - - textures.safeSetTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); - - } - - } - - // Helper to pick the right setter for a pure (bottom-level) array - - function getPureArraySetter( type ) { - - switch ( type ) { - - case 0x1406: return setValueV1fArray; // FLOAT - case 0x8b50: return setValueV2fArray; // _VEC2 - case 0x8b51: return setValueV3fArray; // _VEC3 - case 0x8b52: return setValueV4fArray; // _VEC4 - - case 0x8b5a: return setValueM2Array; // _MAT2 - case 0x8b5b: return setValueM3Array; // _MAT3 - case 0x8b5c: return setValueM4Array; // _MAT4 - - case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL - case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2 - case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3 - case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4 - - case 0x1405: return setValueV1uiArray; // UINT - case 0x8dc6: return setValueV2uiArray; // _VEC2 - case 0x8dc7: return setValueV3uiArray; // _VEC3 - case 0x8dc8: return setValueV4uiArray; // _VEC4 - - case 0x8b5e: // SAMPLER_2D - case 0x8d66: // SAMPLER_EXTERNAL_OES - case 0x8dca: // INT_SAMPLER_2D - case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D - case 0x8b62: // SAMPLER_2D_SHADOW - return setValueT1Array; - - case 0x8b60: // SAMPLER_CUBE - case 0x8dcc: // INT_SAMPLER_CUBE - case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE - case 0x8dc5: // SAMPLER_CUBE_SHADOW - return setValueT6Array; - - } - - } - - // --- Uniform Classes --- - - function SingleUniform( id, activeInfo, addr ) { - - this.id = id; - this.addr = addr; - this.cache = []; - this.setValue = getSingularSetter( activeInfo.type ); - - // this.path = activeInfo.name; // DEBUG - - } - - function PureArrayUniform( id, activeInfo, addr ) { - - this.id = id; - this.addr = addr; - this.cache = []; - this.size = activeInfo.size; - this.setValue = getPureArraySetter( activeInfo.type ); - - // this.path = activeInfo.name; // DEBUG - - } - - PureArrayUniform.prototype.updateCache = function ( data ) { - - const cache = this.cache; - - if ( data instanceof Float32Array && cache.length !== data.length ) { - - this.cache = new Float32Array( data.length ); - - } - - copyArray( cache, data ); - - }; - - function StructuredUniform( id ) { - - this.id = id; - - this.seq = []; - this.map = {}; - - } - - StructuredUniform.prototype.setValue = function ( gl, value, textures ) { - - const seq = this.seq; - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ]; - u.setValue( gl, value[ u.id ], textures ); - - } - - }; - - // --- Top-level --- - - // Parser - builds up the property tree from the path strings - - const RePathPart = /(\w+)(\])?(\[|\.)?/g; - - // extracts - // - the identifier (member name or array index) - // - followed by an optional right bracket (found when array index) - // - followed by an optional left bracket or dot (type of subscript) - // - // Note: These portions can be read in a non-overlapping fashion and - // allow straightforward parsing of the hierarchy that WebGL encodes - // in the uniform names. - - function addUniform( container, uniformObject ) { - - container.seq.push( uniformObject ); - container.map[ uniformObject.id ] = uniformObject; - - } - - function parseUniform( activeInfo, addr, container ) { - - const path = activeInfo.name, - pathLength = path.length; - - // reset RegExp object, because of the early exit of a previous run - RePathPart.lastIndex = 0; - - while ( true ) { - - const match = RePathPart.exec( path ), - matchEnd = RePathPart.lastIndex; - - let id = match[ 1 ]; - const idIsIndex = match[ 2 ] === ']', - subscript = match[ 3 ]; - - if ( idIsIndex ) id = id | 0; // convert to integer - - if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { - - // bare name or "pure" bottom-level array "[0]" suffix - - addUniform( container, subscript === undefined ? - new SingleUniform( id, activeInfo, addr ) : - new PureArrayUniform( id, activeInfo, addr ) ); - - break; - - } else { - - // step into inner node / create it in case it doesn't exist - - const map = container.map; - let next = map[ id ]; - - if ( next === undefined ) { - - next = new StructuredUniform( id ); - addUniform( container, next ); - - } - - container = next; - - } - - } - - } - - // Root Container - - function WebGLUniforms( gl, program ) { - - this.seq = []; - this.map = {}; - - const n = gl.getProgramParameter( program, 35718 ); - - for ( let i = 0; i < n; ++ i ) { - - const info = gl.getActiveUniform( program, i ), - addr = gl.getUniformLocation( program, info.name ); - - parseUniform( info, addr, this ); - - } - - } - - WebGLUniforms.prototype.setValue = function ( gl, name, value, textures ) { - - const u = this.map[ name ]; - - if ( u !== undefined ) u.setValue( gl, value, textures ); - - }; - - WebGLUniforms.prototype.setOptional = function ( gl, object, name ) { - - const v = object[ name ]; - - if ( v !== undefined ) this.setValue( gl, name, v ); - - }; - - - // Static interface - - WebGLUniforms.upload = function ( gl, seq, values, textures ) { - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ], - v = values[ u.id ]; - - if ( v.needsUpdate !== false ) { - - // note: always updating when .needsUpdate is undefined - u.setValue( gl, v.value, textures ); - - } - - } - - }; - - WebGLUniforms.seqWithValue = function ( seq, values ) { - - const r = []; - - for ( let i = 0, n = seq.length; i !== n; ++ i ) { - - const u = seq[ i ]; - if ( u.id in values ) r.push( u ); - - } - - return r; - - }; - - function WebGLShader( gl, type, string ) { - - const shader = gl.createShader( type ); - - gl.shaderSource( shader, string ); - gl.compileShader( shader ); - - return shader; - - } - - let programIdCount = 0; - - function addLineNumbers( string ) { - - const lines = string.split( '\n' ); - - for ( let i = 0; i < lines.length; i ++ ) { - - lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; - - } - - return lines.join( '\n' ); - - } - - function getEncodingComponents( encoding ) { - - switch ( encoding ) { - - case LinearEncoding: - return [ 'Linear', '( value )' ]; - case sRGBEncoding: - return [ 'sRGB', '( value )' ]; - case RGBEEncoding: - return [ 'RGBE', '( value )' ]; - case RGBM7Encoding: - return [ 'RGBM', '( value, 7.0 )' ]; - case RGBM16Encoding: - return [ 'RGBM', '( value, 16.0 )' ]; - case RGBDEncoding: - return [ 'RGBD', '( value, 256.0 )' ]; - case GammaEncoding: - return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ]; - case LogLuvEncoding: - return [ 'LogLuv', '( value )' ]; - default: - console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding ); - return [ 'Linear', '( value )' ]; - - } - - } - - function getShaderErrors( gl, shader, type ) { - - const status = gl.getShaderParameter( shader, 35713 ); - const errors = gl.getShaderInfoLog( shader ).trim(); - - if ( status && errors === '' ) return ''; - - // --enable-privileged-webgl-extension - // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - - return type.toUpperCase() + '\n\n' + errors + '\n\n' + addLineNumbers( gl.getShaderSource( shader ) ); - - } - - function getTexelDecodingFunction( functionName, encoding ) { - - const components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }'; - - } - - function getTexelEncodingFunction( functionName, encoding ) { - - const components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; - - } - - function getToneMappingFunction( functionName, toneMapping ) { - - let toneMappingName; - - switch ( toneMapping ) { - - case LinearToneMapping: - toneMappingName = 'Linear'; - break; - - case ReinhardToneMapping: - toneMappingName = 'Reinhard'; - break; - - case CineonToneMapping: - toneMappingName = 'OptimizedCineon'; - break; - - case ACESFilmicToneMapping: - toneMappingName = 'ACESFilmic'; - break; - - case CustomToneMapping: - toneMappingName = 'Custom'; - break; - - default: - console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping ); - toneMappingName = 'Linear'; - - } - - return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; - - } - - function generateExtensions( parameters ) { - - const chunks = [ - ( parameters.extensionDerivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', - ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', - ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', - ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' - ]; - - return chunks.filter( filterEmptyLine ).join( '\n' ); - - } - - function generateDefines( defines ) { - - const chunks = []; - - for ( const name in defines ) { - - const value = defines[ name ]; - - if ( value === false ) continue; - - chunks.push( '#define ' + name + ' ' + value ); - - } - - return chunks.join( '\n' ); - - } - - function fetchAttributeLocations( gl, program ) { - - const attributes = {}; - - const n = gl.getProgramParameter( program, 35721 ); - - for ( let i = 0; i < n; i ++ ) { - - const info = gl.getActiveAttrib( program, i ); - const name = info.name; - - let locationSize = 1; - if ( info.type === 35674 ) locationSize = 2; - if ( info.type === 35675 ) locationSize = 3; - if ( info.type === 35676 ) locationSize = 4; - - // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); - - attributes[ name ] = { - type: info.type, - location: gl.getAttribLocation( program, name ), - locationSize: locationSize - }; - - } - - return attributes; - - } - - function filterEmptyLine( string ) { - - return string !== ''; - - } - - function replaceLightNums( string, parameters ) { - - return string - .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) - .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) - .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) - .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) - .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ) - .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows ) - .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows ) - .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows ); - - } - - function replaceClippingPlaneNums( string, parameters ) { - - return string - .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) - .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); - - } - - // Resolve Includes - - const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; - - function resolveIncludes( string ) { - - return string.replace( includePattern, includeReplacer ); - - } - - function includeReplacer( match, include ) { - - const string = ShaderChunk[ include ]; - - if ( string === undefined ) { - - throw new Error( 'Can not resolve #include <' + include + '>' ); - - } - - return resolveIncludes( string ); - - } - - // Unroll Loops - - const deprecatedUnrollLoopPattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g; - const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; - - function unrollLoops( string ) { - - return string - .replace( unrollLoopPattern, loopReplacer ) - .replace( deprecatedUnrollLoopPattern, deprecatedLoopReplacer ); - - } - - function deprecatedLoopReplacer( match, start, end, snippet ) { - - console.warn( 'WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead.' ); - return loopReplacer( match, start, end, snippet ); - - } - - function loopReplacer( match, start, end, snippet ) { - - let string = ''; - - for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) { - - string += snippet - .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' ) - .replace( /UNROLLED_LOOP_INDEX/g, i ); - - } - - return string; - - } - - // - - function generatePrecision( parameters ) { - - let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;'; - - if ( parameters.precision === 'highp' ) { - - precisionstring += '\n#define HIGH_PRECISION'; - - } else if ( parameters.precision === 'mediump' ) { - - precisionstring += '\n#define MEDIUM_PRECISION'; - - } else if ( parameters.precision === 'lowp' ) { - - precisionstring += '\n#define LOW_PRECISION'; - - } - - return precisionstring; - - } - - function generateShadowMapTypeDefine( parameters ) { - - let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - - if ( parameters.shadowMapType === PCFShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - - } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - - } else if ( parameters.shadowMapType === VSMShadowMap ) { - - shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; - - } - - return shadowMapTypeDefine; - - } - - function generateEnvMapTypeDefine( parameters ) { - - let envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - - if ( parameters.envMap ) { - - switch ( parameters.envMapMode ) { - - case CubeReflectionMapping: - case CubeRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - break; - - case CubeUVReflectionMapping: - case CubeUVRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; - break; - - } - - } - - return envMapTypeDefine; - - } - - function generateEnvMapModeDefine( parameters ) { - - let envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; - - if ( parameters.envMap ) { - - switch ( parameters.envMapMode ) { - - case CubeRefractionMapping: - case CubeUVRefractionMapping: - - envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; - break; - - } - - } - - return envMapModeDefine; - - } - - function generateEnvMapBlendingDefine( parameters ) { - - let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; - - if ( parameters.envMap ) { - - switch ( parameters.combine ) { - - case MultiplyOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - break; - - case MixOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; - break; - - case AddOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; - break; - - } - - } - - return envMapBlendingDefine; - - } - - function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { - - // TODO Send this event to Three.js DevTools - // console.log( 'WebGLProgram', cacheKey ); - - const gl = renderer.getContext(); - - const defines = parameters.defines; - - let vertexShader = parameters.vertexShader; - let fragmentShader = parameters.fragmentShader; - - const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters ); - const envMapTypeDefine = generateEnvMapTypeDefine( parameters ); - const envMapModeDefine = generateEnvMapModeDefine( parameters ); - const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters ); - - - const gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; - - const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); - - const customDefines = generateDefines( defines ); - - const program = gl.createProgram(); - - let prefixVertex, prefixFragment; - let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; - - if ( parameters.isRawShaderMaterial ) { - - prefixVertex = [ - - customDefines - - ].filter( filterEmptyLine ).join( '\n' ); - - if ( prefixVertex.length > 0 ) { - - prefixVertex += '\n'; - - } - - prefixFragment = [ - - customExtensions, - customDefines - - ].filter( filterEmptyLine ).join( '\n' ); - - if ( prefixFragment.length > 0 ) { - - prefixFragment += '\n'; - - } - - } else { - - prefixVertex = [ - - generatePrecision( parameters ), - - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines, - - parameters.instancing ? '#define USE_INSTANCING' : '', - parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', - - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - - '#define GAMMA_FACTOR ' + gammaFactorDefine, - - '#define MAX_BONES ' + parameters.maxBones, - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', - - parameters.map ? '#define USE_MAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', - - parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', - parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', - parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', - - parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', - - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularTintMap ? '#define USE_SPECULARTINTMAP' : '', - - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - - parameters.transmission ? '#define USE_TRANSMISSION' : '', - parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - - parameters.vertexTangents ? '#define USE_TANGENT' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', - parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', - - parameters.flatShading ? '#define FLAT_SHADED' : '', - - parameters.skinning ? '#define USE_SKINNING' : '', - parameters.useVertexTexture ? '#define BONE_TEXTURE' : '', - - parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', - parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - - parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - - 'uniform mat4 modelMatrix;', - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform mat4 viewMatrix;', - 'uniform mat3 normalMatrix;', - 'uniform vec3 cameraPosition;', - 'uniform bool isOrthographic;', - - '#ifdef USE_INSTANCING', - - ' attribute mat4 instanceMatrix;', - - '#endif', - - '#ifdef USE_INSTANCING_COLOR', - - ' attribute vec3 instanceColor;', - - '#endif', - - 'attribute vec3 position;', - 'attribute vec3 normal;', - 'attribute vec2 uv;', - - '#ifdef USE_TANGENT', - - ' attribute vec4 tangent;', - - '#endif', - - '#if defined( USE_COLOR_ALPHA )', - - ' attribute vec4 color;', - - '#elif defined( USE_COLOR )', - - ' attribute vec3 color;', - - '#endif', - - '#ifdef USE_MORPHTARGETS', - - ' attribute vec3 morphTarget0;', - ' attribute vec3 morphTarget1;', - ' attribute vec3 morphTarget2;', - ' attribute vec3 morphTarget3;', - - ' #ifdef USE_MORPHNORMALS', - - ' attribute vec3 morphNormal0;', - ' attribute vec3 morphNormal1;', - ' attribute vec3 morphNormal2;', - ' attribute vec3 morphNormal3;', - - ' #else', - - ' attribute vec3 morphTarget4;', - ' attribute vec3 morphTarget5;', - ' attribute vec3 morphTarget6;', - ' attribute vec3 morphTarget7;', - - ' #endif', - - '#endif', - - '#ifdef USE_SKINNING', - - ' attribute vec4 skinIndex;', - ' attribute vec4 skinWeight;', - - '#endif', - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - prefixFragment = [ - - customExtensions, - - generatePrecision( parameters ), - - '#define SHADER_NAME ' + parameters.shaderName, - - customDefines, - - '#define GAMMA_FACTOR ' + gammaFactorDefine, - - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', - - parameters.map ? '#define USE_MAP' : '', - parameters.matcap ? '#define USE_MATCAP' : '', - parameters.envMap ? '#define USE_ENVMAP' : '', - parameters.envMap ? '#define ' + envMapTypeDefine : '', - parameters.envMap ? '#define ' + envMapModeDefine : '', - parameters.envMap ? '#define ' + envMapBlendingDefine : '', - parameters.lightMap ? '#define USE_LIGHTMAP' : '', - parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', - parameters.bumpMap ? '#define USE_BUMPMAP' : '', - parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', - - parameters.clearcoat ? '#define USE_CLEARCOAT' : '', - parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', - parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', - parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', - - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularTintMap ? '#define USE_SPECULARTINTMAP' : '', - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.alphaTest ? '#define USE_ALPHATEST' : '', - - parameters.sheenTint ? '#define USE_SHEEN' : '', - parameters.transmission ? '#define USE_TRANSMISSION' : '', - parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - - parameters.vertexTangents ? '#define USE_TANGENT' : '', - parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', - parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', - - parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', - - parameters.flatShading ? '#define FLAT_SHADED' : '', - - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', - - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - - parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - - parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', - - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - - ( ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ) ? '#define TEXTURE_LOD_EXT' : '', - - 'uniform mat4 viewMatrix;', - 'uniform vec3 cameraPosition;', - 'uniform bool isOrthographic;', - - ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '', - ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below - ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '', - - parameters.dithering ? '#define DITHERING' : '', - parameters.format === RGBFormat ? '#define OPAQUE' : '', - - ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below - parameters.map ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '', - parameters.matcap ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '', - parameters.envMap ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '', - parameters.emissiveMap ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '', - parameters.specularTintMap ? getTexelDecodingFunction( 'specularTintMapTexelToLinear', parameters.specularTintMapEncoding ) : '', - parameters.lightMap ? getTexelDecodingFunction( 'lightMapTexelToLinear', parameters.lightMapEncoding ) : '', - getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ), - - parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', - - '\n' - - ].filter( filterEmptyLine ).join( '\n' ); - - } - - vertexShader = resolveIncludes( vertexShader ); - vertexShader = replaceLightNums( vertexShader, parameters ); - vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); - - fragmentShader = resolveIncludes( fragmentShader ); - fragmentShader = replaceLightNums( fragmentShader, parameters ); - fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); - - vertexShader = unrollLoops( vertexShader ); - fragmentShader = unrollLoops( fragmentShader ); - - if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) { - - // GLSL 3.0 conversion for built-in materials and ShaderMaterial - - versionString = '#version 300 es\n'; - - prefixVertex = [ - '#define attribute in', - '#define varying out', - '#define texture2D texture' - ].join( '\n' ) + '\n' + prefixVertex; - - prefixFragment = [ - '#define varying in', - ( parameters.glslVersion === GLSL3 ) ? '' : 'out highp vec4 pc_fragColor;', - ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', - '#define gl_FragDepthEXT gl_FragDepth', - '#define texture2D texture', - '#define textureCube texture', - '#define texture2DProj textureProj', - '#define texture2DLodEXT textureLod', - '#define texture2DProjLodEXT textureProjLod', - '#define textureCubeLodEXT textureLod', - '#define texture2DGradEXT textureGrad', - '#define texture2DProjGradEXT textureProjGrad', - '#define textureCubeGradEXT textureGrad' - ].join( '\n' ) + '\n' + prefixFragment; - - } - - const vertexGlsl = versionString + prefixVertex + vertexShader; - const fragmentGlsl = versionString + prefixFragment + fragmentShader; - - // console.log( '*VERTEX*', vertexGlsl ); - // console.log( '*FRAGMENT*', fragmentGlsl ); - - const glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); - const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); - - gl.attachShader( program, glVertexShader ); - gl.attachShader( program, glFragmentShader ); - - // Force a particular attribute to index 0. - - if ( parameters.index0AttributeName !== undefined ) { - - gl.bindAttribLocation( program, 0, parameters.index0AttributeName ); - - } else if ( parameters.morphTargets === true ) { - - // programs with morphTargets displace position out of attribute 0 - gl.bindAttribLocation( program, 0, 'position' ); - - } - - gl.linkProgram( program ); - - // check for link errors - if ( renderer.debug.checkShaderErrors ) { - - const programLog = gl.getProgramInfoLog( program ).trim(); - const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); - const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); - - let runnable = true; - let haveDiagnostics = true; - - if ( gl.getProgramParameter( program, 35714 ) === false ) { - - runnable = false; - - const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); - const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); - - console.error( - 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + - 'VALIDATE_STATUS ' + gl.getProgramParameter( program, 35715 ) + '\n\n' + - 'Program Info Log: ' + programLog + '\n' + - vertexErrors + '\n' + - fragmentErrors - ); - - } else if ( programLog !== '' ) { - - console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); - - } else if ( vertexLog === '' || fragmentLog === '' ) { - - haveDiagnostics = false; - - } - - if ( haveDiagnostics ) { - - this.diagnostics = { - - runnable: runnable, - - programLog: programLog, - - vertexShader: { - - log: vertexLog, - prefix: prefixVertex - - }, - - fragmentShader: { - - log: fragmentLog, - prefix: prefixFragment - - } - - }; - - } - - } - - // Clean up - - // Crashes in iOS9 and iOS10. #18402 - // gl.detachShader( program, glVertexShader ); - // gl.detachShader( program, glFragmentShader ); - - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); - - // set up caching for uniform locations - - let cachedUniforms; - - this.getUniforms = function () { - - if ( cachedUniforms === undefined ) { - - cachedUniforms = new WebGLUniforms( gl, program ); - - } - - return cachedUniforms; - - }; - - // set up caching for attribute locations - - let cachedAttributes; - - this.getAttributes = function () { - - if ( cachedAttributes === undefined ) { - - cachedAttributes = fetchAttributeLocations( gl, program ); - - } - - return cachedAttributes; - - }; - - // free resource - - this.destroy = function () { - - bindingStates.releaseStatesOfProgram( this ); - - gl.deleteProgram( program ); - this.program = undefined; - - }; - - // - - this.name = parameters.shaderName; - this.id = programIdCount ++; - this.cacheKey = cacheKey; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; - - return this; - - } - - function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) { - - const programs = []; - - const isWebGL2 = capabilities.isWebGL2; - const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; - const floatVertexTextures = capabilities.floatVertexTextures; - const maxVertexUniforms = capabilities.maxVertexUniforms; - const vertexTextures = capabilities.vertexTextures; - - let precision = capabilities.precision; - - const shaderIDs = { - MeshDepthMaterial: 'depth', - MeshDistanceMaterial: 'distanceRGBA', - MeshNormalMaterial: 'normal', - MeshBasicMaterial: 'basic', - MeshLambertMaterial: 'lambert', - MeshPhongMaterial: 'phong', - MeshToonMaterial: 'toon', - MeshStandardMaterial: 'physical', - MeshPhysicalMaterial: 'physical', - MeshMatcapMaterial: 'matcap', - LineBasicMaterial: 'basic', - LineDashedMaterial: 'dashed', - PointsMaterial: 'points', - ShadowMaterial: 'shadow', - SpriteMaterial: 'sprite' - }; - - const parameterNames = [ - 'precision', 'isWebGL2', 'supportsVertexTextures', 'outputEncoding', 'instancing', 'instancingColor', - 'map', 'mapEncoding', 'matcap', 'matcapEncoding', 'envMap', 'envMapMode', 'envMapEncoding', 'envMapCubeUV', - 'lightMap', 'lightMapEncoding', 'aoMap', 'emissiveMap', 'emissiveMapEncoding', 'bumpMap', 'normalMap', - 'objectSpaceNormalMap', 'tangentSpaceNormalMap', - 'clearcoat', 'clearcoatMap', 'clearcoatRoughnessMap', 'clearcoatNormalMap', - 'displacementMap', - 'specularMap', 'specularIntensityMap', 'specularTintMap', 'specularTintMapEncoding', 'roughnessMap', 'metalnessMap', 'gradientMap', - 'alphaMap', 'alphaTest', 'combine', 'vertexColors', 'vertexAlphas', 'vertexTangents', 'vertexUvs', 'uvsVertexOnly', 'fog', 'useFog', 'fogExp2', - 'flatShading', 'sizeAttenuation', 'logarithmicDepthBuffer', 'skinning', - 'maxBones', 'useVertexTexture', 'morphTargets', 'morphNormals', 'premultipliedAlpha', - 'numDirLights', 'numPointLights', 'numSpotLights', 'numHemiLights', 'numRectAreaLights', - 'numDirLightShadows', 'numPointLightShadows', 'numSpotLightShadows', - 'shadowMapEnabled', 'shadowMapType', 'toneMapping', 'physicallyCorrectLights', - 'doubleSided', 'flipSided', 'numClippingPlanes', 'numClipIntersection', 'depthPacking', 'dithering', 'format', - 'sheenTint', 'transmission', 'transmissionMap', 'thicknessMap' - ]; - - function getMaxBones( object ) { - - const skeleton = object.skeleton; - const bones = skeleton.bones; - - if ( floatVertexTextures ) { - - return 1024; - - } else { - - // default for when object is not specified - // ( for example when prebuilding shader to be used with multiple objects ) - // - // - leave some extra space for other uniforms - // - limit here is ANGLE's 254 max uniform vectors - // (up to 54 should be safe) - - const nVertexUniforms = maxVertexUniforms; - const nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); - - const maxBones = Math.min( nVertexMatrices, bones.length ); - - if ( maxBones < bones.length ) { - - console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' ); - return 0; - - } - - return maxBones; - - } - - } - - function getTextureEncodingFromMap( map ) { - - let encoding; - - if ( map && map.isTexture ) { - - encoding = map.encoding; - - } else if ( map && map.isWebGLRenderTarget ) { - - console.warn( 'THREE.WebGLPrograms.getTextureEncodingFromMap: don\'t use render targets as textures. Use their .texture property instead.' ); - encoding = map.texture.encoding; - - } else { - - encoding = LinearEncoding; - - } - - return encoding; - - } - - function getParameters( material, lights, shadows, scene, object ) { - - const fog = scene.fog; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - - const shaderID = shaderIDs[ material.type ]; - - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) - - const maxBones = object.isSkinnedMesh ? getMaxBones( object ) : 0; - - if ( material.precision !== null ) { - - precision = capabilities.getMaxPrecision( material.precision ); - - if ( precision !== material.precision ) { - - console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); - - } - - } - - let vertexShader, fragmentShader; - - if ( shaderID ) { - - const shader = ShaderLib[ shaderID ]; - - vertexShader = shader.vertexShader; - fragmentShader = shader.fragmentShader; - - } else { - - vertexShader = material.vertexShader; - fragmentShader = material.fragmentShader; - - } - - const currentRenderTarget = renderer.getRenderTarget(); - - const useAlphaTest = material.alphaTest > 0; - const useClearcoat = material.clearcoat > 0; - - const parameters = { - - isWebGL2: isWebGL2, - - shaderID: shaderID, - shaderName: material.type, - - vertexShader: vertexShader, - fragmentShader: fragmentShader, - defines: material.defines, - - isRawShaderMaterial: material.isRawShaderMaterial === true, - glslVersion: material.glslVersion, - - precision: precision, - - instancing: object.isInstancedMesh === true, - instancingColor: object.isInstancedMesh === true && object.instanceColor !== null, - - supportsVertexTextures: vertexTextures, - outputEncoding: ( currentRenderTarget !== null ) ? getTextureEncodingFromMap( currentRenderTarget.texture ) : renderer.outputEncoding, - map: !! material.map, - mapEncoding: getTextureEncodingFromMap( material.map ), - matcap: !! material.matcap, - matcapEncoding: getTextureEncodingFromMap( material.matcap ), - envMap: !! envMap, - envMapMode: envMap && envMap.mapping, - envMapEncoding: getTextureEncodingFromMap( envMap ), - envMapCubeUV: ( !! envMap ) && ( ( envMap.mapping === CubeUVReflectionMapping ) || ( envMap.mapping === CubeUVRefractionMapping ) ), - lightMap: !! material.lightMap, - lightMapEncoding: getTextureEncodingFromMap( material.lightMap ), - aoMap: !! material.aoMap, - emissiveMap: !! material.emissiveMap, - emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap ), - bumpMap: !! material.bumpMap, - normalMap: !! material.normalMap, - objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, - tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap, - - clearcoat: useClearcoat, - clearcoatMap: useClearcoat && !! material.clearcoatMap, - clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap, - clearcoatNormalMap: useClearcoat && !! material.clearcoatNormalMap, - - displacementMap: !! material.displacementMap, - roughnessMap: !! material.roughnessMap, - metalnessMap: !! material.metalnessMap, - specularMap: !! material.specularMap, - specularIntensityMap: !! material.specularIntensityMap, - specularTintMap: !! material.specularTintMap, - specularTintMapEncoding: getTextureEncodingFromMap( material.specularTintMap ), - - alphaMap: !! material.alphaMap, - alphaTest: useAlphaTest, - - gradientMap: !! material.gradientMap, - - sheenTint: ( !! material.sheenTint && ( material.sheenTint.r > 0 || material.sheenTint.g > 0 || material.sheenTint.b > 0 ) ), - - transmission: material.transmission > 0, - transmissionMap: !! material.transmissionMap, - thicknessMap: !! material.thicknessMap, - - combine: material.combine, - - vertexTangents: ( !! material.normalMap && !! object.geometry && !! object.geometry.attributes.tangent ), - vertexColors: material.vertexColors, - vertexAlphas: material.vertexColors === true && !! object.geometry && !! object.geometry.attributes.color && object.geometry.attributes.color.itemSize === 4, - vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularTintMap, - uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularTintMap ) && !! material.displacementMap, - - fog: !! fog, - useFog: material.fog, - fogExp2: ( fog && fog.isFogExp2 ), - - flatShading: !! material.flatShading, - - sizeAttenuation: material.sizeAttenuation, - logarithmicDepthBuffer: logarithmicDepthBuffer, - - skinning: object.isSkinnedMesh === true && maxBones > 0, - maxBones: maxBones, - useVertexTexture: floatVertexTextures, - - morphTargets: !! object.geometry && !! object.geometry.morphAttributes.position, - morphNormals: !! object.geometry && !! object.geometry.morphAttributes.normal, - - numDirLights: lights.directional.length, - numPointLights: lights.point.length, - numSpotLights: lights.spot.length, - numRectAreaLights: lights.rectArea.length, - numHemiLights: lights.hemi.length, - - numDirLightShadows: lights.directionalShadowMap.length, - numPointLightShadows: lights.pointShadowMap.length, - numSpotLightShadows: lights.spotShadowMap.length, - - numClippingPlanes: clipping.numPlanes, - numClipIntersection: clipping.numIntersection, - - format: material.format, - dithering: material.dithering, - - shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, - shadowMapType: renderer.shadowMap.type, - - toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping, - physicallyCorrectLights: renderer.physicallyCorrectLights, - - premultipliedAlpha: material.premultipliedAlpha, - - doubleSided: material.side === DoubleSide, - flipSided: material.side === BackSide, - - depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false, - - index0AttributeName: material.index0AttributeName, - - extensionDerivatives: material.extensions && material.extensions.derivatives, - extensionFragDepth: material.extensions && material.extensions.fragDepth, - extensionDrawBuffers: material.extensions && material.extensions.drawBuffers, - extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD, - - rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ), - rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ), - rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ), - - customProgramCacheKey: material.customProgramCacheKey() - - }; - - return parameters; - - } - - function getProgramCacheKey( parameters ) { - - const array = []; - - if ( parameters.shaderID ) { - - array.push( parameters.shaderID ); - - } else { - - array.push( parameters.fragmentShader ); - array.push( parameters.vertexShader ); - - } - - if ( parameters.defines !== undefined ) { - - for ( const name in parameters.defines ) { - - array.push( name ); - array.push( parameters.defines[ name ] ); - - } - - } - - if ( parameters.isRawShaderMaterial === false ) { - - for ( let i = 0; i < parameterNames.length; i ++ ) { - - array.push( parameters[ parameterNames[ i ] ] ); - - } - - array.push( renderer.outputEncoding ); - array.push( renderer.gammaFactor ); - - } - - array.push( parameters.customProgramCacheKey ); - - return array.join(); - - } - - function getUniforms( material ) { - - const shaderID = shaderIDs[ material.type ]; - let uniforms; - - if ( shaderID ) { - - const shader = ShaderLib[ shaderID ]; - uniforms = UniformsUtils.clone( shader.uniforms ); - - } else { - - uniforms = material.uniforms; - - } - - return uniforms; - - } - - function acquireProgram( parameters, cacheKey ) { - - let program; - - // Check if code has been already compiled - for ( let p = 0, pl = programs.length; p < pl; p ++ ) { - - const preexistingProgram = programs[ p ]; - - if ( preexistingProgram.cacheKey === cacheKey ) { - - program = preexistingProgram; - ++ program.usedTimes; - - break; - - } - - } - - if ( program === undefined ) { - - program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates ); - programs.push( program ); - - } - - return program; - - } - - function releaseProgram( program ) { - - if ( -- program.usedTimes === 0 ) { - - // Remove from unordered set - const i = programs.indexOf( program ); - programs[ i ] = programs[ programs.length - 1 ]; - programs.pop(); - - // Free WebGL resources - program.destroy(); - - } - - } - - return { - getParameters: getParameters, - getProgramCacheKey: getProgramCacheKey, - getUniforms: getUniforms, - acquireProgram: acquireProgram, - releaseProgram: releaseProgram, - // Exposed for resource monitoring & error feedback via renderer.info: - programs: programs - }; - - } - - function WebGLProperties() { - - let properties = new WeakMap(); - - function get( object ) { - - let map = properties.get( object ); - - if ( map === undefined ) { - - map = {}; - properties.set( object, map ); - - } - - return map; - - } - - function remove( object ) { - - properties.delete( object ); - - } - - function update( object, key, value ) { - - properties.get( object )[ key ] = value; - - } - - function dispose() { - - properties = new WeakMap(); - - } - - return { - get: get, - remove: remove, - update: update, - dispose: dispose - }; - - } - - function painterSortStable( a, b ) { - - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; - - } else if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.program !== b.program ) { - - return a.program.id - b.program.id; - - } else if ( a.material.id !== b.material.id ) { - - return a.material.id - b.material.id; - - } else if ( a.z !== b.z ) { - - return a.z - b.z; - - } else { - - return a.id - b.id; - - } - - } - - function reversePainterSortStable( a, b ) { - - if ( a.groupOrder !== b.groupOrder ) { - - return a.groupOrder - b.groupOrder; - - } else if ( a.renderOrder !== b.renderOrder ) { - - return a.renderOrder - b.renderOrder; - - } else if ( a.z !== b.z ) { - - return b.z - a.z; - - } else { - - return a.id - b.id; - - } - - } - - - function WebGLRenderList( properties ) { - - const renderItems = []; - let renderItemsIndex = 0; - - const opaque = []; - const transmissive = []; - const transparent = []; - - const defaultProgram = { id: - 1 }; - - function init() { - - renderItemsIndex = 0; - - opaque.length = 0; - transmissive.length = 0; - transparent.length = 0; - - } - - function getNextRenderItem( object, geometry, material, groupOrder, z, group ) { - - let renderItem = renderItems[ renderItemsIndex ]; - const materialProperties = properties.get( material ); - - if ( renderItem === undefined ) { - - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - program: materialProperties.program || defaultProgram, - groupOrder: groupOrder, - renderOrder: object.renderOrder, - z: z, - group: group - }; - - renderItems[ renderItemsIndex ] = renderItem; - - } else { - - renderItem.id = object.id; - renderItem.object = object; - renderItem.geometry = geometry; - renderItem.material = material; - renderItem.program = materialProperties.program || defaultProgram; - renderItem.groupOrder = groupOrder; - renderItem.renderOrder = object.renderOrder; - renderItem.z = z; - renderItem.group = group; - - } - - renderItemsIndex ++; - - return renderItem; - - } - - function push( object, geometry, material, groupOrder, z, group ) { - - const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - - if ( material.transmission > 0.0 ) { - - transmissive.push( renderItem ); - - } else if ( material.transparent === true ) { - - transparent.push( renderItem ); - - } else { - - opaque.push( renderItem ); - - } - - } - - function unshift( object, geometry, material, groupOrder, z, group ) { - - const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - - if ( material.transmission > 0.0 ) { - - transmissive.unshift( renderItem ); - - } else if ( material.transparent === true ) { - - transparent.unshift( renderItem ); - - } else { - - opaque.unshift( renderItem ); - - } - - } - - function sort( customOpaqueSort, customTransparentSort ) { - - if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable ); - if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable ); - if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable ); - - } - - function finish() { - - // Clear references from inactive renderItems in the list - - for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) { - - const renderItem = renderItems[ i ]; - - if ( renderItem.id === null ) break; - - renderItem.id = null; - renderItem.object = null; - renderItem.geometry = null; - renderItem.material = null; - renderItem.program = null; - renderItem.group = null; - - } - - } - - return { - - opaque: opaque, - transmissive: transmissive, - transparent: transparent, - - init: init, - push: push, - unshift: unshift, - finish: finish, - - sort: sort - }; - - } - - function WebGLRenderLists( properties ) { - - let lists = new WeakMap(); - - function get( scene, renderCallDepth ) { - - let list; - - if ( lists.has( scene ) === false ) { - - list = new WebGLRenderList( properties ); - lists.set( scene, [ list ] ); - - } else { - - if ( renderCallDepth >= lists.get( scene ).length ) { - - list = new WebGLRenderList( properties ); - lists.get( scene ).push( list ); - - } else { - - list = lists.get( scene )[ renderCallDepth ]; - - } - - } - - return list; - - } - - function dispose() { - - lists = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - - } - - function UniformsCache() { - - const lights = {}; - - return { - - get: function ( light ) { - - if ( lights[ light.id ] !== undefined ) { - - return lights[ light.id ]; - - } - - let uniforms; - - switch ( light.type ) { - - case 'DirectionalLight': - uniforms = { - direction: new Vector3(), - color: new Color() - }; - break; - - case 'SpotLight': - uniforms = { - position: new Vector3(), - direction: new Vector3(), - color: new Color(), - distance: 0, - coneCos: 0, - penumbraCos: 0, - decay: 0 - }; - break; - - case 'PointLight': - uniforms = { - position: new Vector3(), - color: new Color(), - distance: 0, - decay: 0 - }; - break; - - case 'HemisphereLight': - uniforms = { - direction: new Vector3(), - skyColor: new Color(), - groundColor: new Color() - }; - break; - - case 'RectAreaLight': - uniforms = { - color: new Color(), - position: new Vector3(), - halfWidth: new Vector3(), - halfHeight: new Vector3() - }; - break; - - } - - lights[ light.id ] = uniforms; - - return uniforms; - - } - - }; - - } - - function ShadowUniformsCache() { - - const lights = {}; - - return { - - get: function ( light ) { - - if ( lights[ light.id ] !== undefined ) { - - return lights[ light.id ]; - - } - - let uniforms; - - switch ( light.type ) { - - case 'DirectionalLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'SpotLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; - - case 'PointLight': - uniforms = { - shadowBias: 0, - shadowNormalBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2(), - shadowCameraNear: 1, - shadowCameraFar: 1000 - }; - break; - - // TODO (abelnation): set RectAreaLight shadow uniforms - - } - - lights[ light.id ] = uniforms; - - return uniforms; - - } - - }; - - } - - - - let nextVersion = 0; - - function shadowCastingLightsFirst( lightA, lightB ) { - - return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 ); - - } - - function WebGLLights( extensions, capabilities ) { - - const cache = new UniformsCache(); - - const shadowCache = ShadowUniformsCache(); - - const state = { - - version: 0, - - hash: { - directionalLength: - 1, - pointLength: - 1, - spotLength: - 1, - rectAreaLength: - 1, - hemiLength: - 1, - - numDirectionalShadows: - 1, - numPointShadows: - 1, - numSpotShadows: - 1 - }, - - ambient: [ 0, 0, 0 ], - probe: [], - directional: [], - directionalShadow: [], - directionalShadowMap: [], - directionalShadowMatrix: [], - spot: [], - spotShadow: [], - spotShadowMap: [], - spotShadowMatrix: [], - rectArea: [], - rectAreaLTC1: null, - rectAreaLTC2: null, - point: [], - pointShadow: [], - pointShadowMap: [], - pointShadowMatrix: [], - hemi: [] - - }; - - for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() ); - - const vector3 = new Vector3(); - const matrix4 = new Matrix4(); - const matrix42 = new Matrix4(); - - function setup( lights, physicallyCorrectLights ) { - - let r = 0, g = 0, b = 0; - - for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 ); - - let directionalLength = 0; - let pointLength = 0; - let spotLength = 0; - let rectAreaLength = 0; - let hemiLength = 0; - - let numDirectionalShadows = 0; - let numPointShadows = 0; - let numSpotShadows = 0; - - lights.sort( shadowCastingLightsFirst ); - - // artist-friendly light intensity scaling factor - const scaleFactor = ( physicallyCorrectLights !== true ) ? Math.PI : 1; - - for ( let i = 0, l = lights.length; i < l; i ++ ) { - - const light = lights[ i ]; - - const color = light.color; - const intensity = light.intensity; - const distance = light.distance; - - const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; - - if ( light.isAmbientLight ) { - - r += color.r * intensity * scaleFactor; - g += color.g * intensity * scaleFactor; - b += color.b * intensity * scaleFactor; - - } else if ( light.isLightProbe ) { - - for ( let j = 0; j < 9; j ++ ) { - - state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity ); - - } - - } else if ( light.isDirectionalLight ) { - - const uniforms = cache.get( light ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); - - if ( light.castShadow ) { - - const shadow = light.shadow; - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - - state.directionalShadow[ directionalLength ] = shadowUniforms; - state.directionalShadowMap[ directionalLength ] = shadowMap; - state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - - numDirectionalShadows ++; - - } - - state.directional[ directionalLength ] = uniforms; - - directionalLength ++; - - } else if ( light.isSpotLight ) { - - const uniforms = cache.get( light ); - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - - uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor ); - uniforms.distance = distance; - - uniforms.coneCos = Math.cos( light.angle ); - uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); - uniforms.decay = light.decay; - - if ( light.castShadow ) { - - const shadow = light.shadow; - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - - state.spotShadow[ spotLength ] = shadowUniforms; - state.spotShadowMap[ spotLength ] = shadowMap; - state.spotShadowMatrix[ spotLength ] = light.shadow.matrix; - - numSpotShadows ++; - - } - - state.spot[ spotLength ] = uniforms; - - spotLength ++; - - } else if ( light.isRectAreaLight ) { - - const uniforms = cache.get( light ); - - // (a) intensity is the total visible light emitted - //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) ); - - // (b) intensity is the brightness of the light - uniforms.color.copy( color ).multiplyScalar( intensity ); - - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - - state.rectArea[ rectAreaLength ] = uniforms; - - rectAreaLength ++; - - } else if ( light.isPointLight ) { - - const uniforms = cache.get( light ); - - uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); - uniforms.distance = light.distance; - uniforms.decay = light.decay; - - if ( light.castShadow ) { - - const shadow = light.shadow; - - const shadowUniforms = shadowCache.get( light ); - - shadowUniforms.shadowBias = shadow.bias; - shadowUniforms.shadowNormalBias = shadow.normalBias; - shadowUniforms.shadowRadius = shadow.radius; - shadowUniforms.shadowMapSize = shadow.mapSize; - shadowUniforms.shadowCameraNear = shadow.camera.near; - shadowUniforms.shadowCameraFar = shadow.camera.far; - - state.pointShadow[ pointLength ] = shadowUniforms; - state.pointShadowMap[ pointLength ] = shadowMap; - state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; - - numPointShadows ++; - - } - - state.point[ pointLength ] = uniforms; - - pointLength ++; - - } else if ( light.isHemisphereLight ) { - - const uniforms = cache.get( light ); - - uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor ); - uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor ); - - state.hemi[ hemiLength ] = uniforms; - - hemiLength ++; - - } - - } - - if ( rectAreaLength > 0 ) { - - if ( capabilities.isWebGL2 ) { - - // WebGL 2 - - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; - - } else { - - // WebGL 1 - - if ( extensions.has( 'OES_texture_float_linear' ) === true ) { - - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; - - } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) { - - state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; - state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; - - } else { - - console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' ); - - } - - } - - } - - state.ambient[ 0 ] = r; - state.ambient[ 1 ] = g; - state.ambient[ 2 ] = b; - - const hash = state.hash; - - if ( hash.directionalLength !== directionalLength || - hash.pointLength !== pointLength || - hash.spotLength !== spotLength || - hash.rectAreaLength !== rectAreaLength || - hash.hemiLength !== hemiLength || - hash.numDirectionalShadows !== numDirectionalShadows || - hash.numPointShadows !== numPointShadows || - hash.numSpotShadows !== numSpotShadows ) { - - state.directional.length = directionalLength; - state.spot.length = spotLength; - state.rectArea.length = rectAreaLength; - state.point.length = pointLength; - state.hemi.length = hemiLength; - - state.directionalShadow.length = numDirectionalShadows; - state.directionalShadowMap.length = numDirectionalShadows; - state.pointShadow.length = numPointShadows; - state.pointShadowMap.length = numPointShadows; - state.spotShadow.length = numSpotShadows; - state.spotShadowMap.length = numSpotShadows; - state.directionalShadowMatrix.length = numDirectionalShadows; - state.pointShadowMatrix.length = numPointShadows; - state.spotShadowMatrix.length = numSpotShadows; - - hash.directionalLength = directionalLength; - hash.pointLength = pointLength; - hash.spotLength = spotLength; - hash.rectAreaLength = rectAreaLength; - hash.hemiLength = hemiLength; - - hash.numDirectionalShadows = numDirectionalShadows; - hash.numPointShadows = numPointShadows; - hash.numSpotShadows = numSpotShadows; - - state.version = nextVersion ++; - - } - - } - - function setupView( lights, camera ) { - - let directionalLength = 0; - let pointLength = 0; - let spotLength = 0; - let rectAreaLength = 0; - let hemiLength = 0; - - const viewMatrix = camera.matrixWorldInverse; - - for ( let i = 0, l = lights.length; i < l; i ++ ) { - - const light = lights[ i ]; - - if ( light.isDirectionalLight ) { - - const uniforms = state.directional[ directionalLength ]; - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); - - directionalLength ++; - - } else if ( light.isSpotLight ) { - - const uniforms = state.spot[ spotLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); - - spotLength ++; - - } else if ( light.isRectAreaLight ) { - - const uniforms = state.rectArea[ rectAreaLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - // extract local rotation of light to derive width/height half vectors - matrix42.identity(); - matrix4.copy( light.matrixWorld ); - matrix4.premultiply( viewMatrix ); - matrix42.extractRotation( matrix4 ); - - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - - uniforms.halfWidth.applyMatrix4( matrix42 ); - uniforms.halfHeight.applyMatrix4( matrix42 ); - - rectAreaLength ++; - - } else if ( light.isPointLight ) { - - const uniforms = state.point[ pointLength ]; - - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); - - pointLength ++; - - } else if ( light.isHemisphereLight ) { - - const uniforms = state.hemi[ hemiLength ]; - - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - uniforms.direction.transformDirection( viewMatrix ); - uniforms.direction.normalize(); - - hemiLength ++; - - } - - } - - } - - return { - setup: setup, - setupView: setupView, - state: state - }; - - } - - function WebGLRenderState( extensions, capabilities ) { - - const lights = new WebGLLights( extensions, capabilities ); - - const lightsArray = []; - const shadowsArray = []; - - function init() { - - lightsArray.length = 0; - shadowsArray.length = 0; - - } - - function pushLight( light ) { - - lightsArray.push( light ); - - } - - function pushShadow( shadowLight ) { - - shadowsArray.push( shadowLight ); - - } - - function setupLights( physicallyCorrectLights ) { - - lights.setup( lightsArray, physicallyCorrectLights ); - - } - - function setupLightsView( camera ) { - - lights.setupView( lightsArray, camera ); - - } - - const state = { - lightsArray: lightsArray, - shadowsArray: shadowsArray, - - lights: lights - }; - - return { - init: init, - state: state, - setupLights: setupLights, - setupLightsView: setupLightsView, - - pushLight: pushLight, - pushShadow: pushShadow - }; - - } - - function WebGLRenderStates( extensions, capabilities ) { - - let renderStates = new WeakMap(); - - function get( scene, renderCallDepth = 0 ) { - - let renderState; - - if ( renderStates.has( scene ) === false ) { - - renderState = new WebGLRenderState( extensions, capabilities ); - renderStates.set( scene, [ renderState ] ); - - } else { - - if ( renderCallDepth >= renderStates.get( scene ).length ) { - - renderState = new WebGLRenderState( extensions, capabilities ); - renderStates.get( scene ).push( renderState ); - - } else { - - renderState = renderStates.get( scene )[ renderCallDepth ]; - - } - - } - - return renderState; - - } - - function dispose() { - - renderStates = new WeakMap(); - - } - - return { - get: get, - dispose: dispose - }; - - } - - /** - * parameters = { - * - * opacity: , - * - * map: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ - - class MeshDepthMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'MeshDepthMaterial'; - - this.depthPacking = BasicDepthPacking; - - this.map = null; - - this.alphaMap = null; - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.depthPacking = source.depthPacking; - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - return this; - - } - - } - - MeshDepthMaterial.prototype.isMeshDepthMaterial = true; - - /** - * parameters = { - * - * referencePosition: , - * nearDistance: , - * farDistance: , - * - * map: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: - * - * } - */ - - class MeshDistanceMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'MeshDistanceMaterial'; - - this.referencePosition = new Vector3(); - this.nearDistance = 1; - this.farDistance = 1000; - - this.map = null; - - this.alphaMap = null; - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.fog = false; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.referencePosition.copy( source.referencePosition ); - this.nearDistance = source.nearDistance; - this.farDistance = source.farDistance; - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - return this; - - } - - } - - MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true; - - var vsm_frag = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\nuniform float samples;\n#include \nvoid main() {\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"; - - var vsm_vert = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; - - function WebGLShadowMap( _renderer, _objects, _capabilities ) { - - let _frustum = new Frustum(); - - const _shadowMapSize = new Vector2(), - _viewportSize = new Vector2(), - - _viewport = new Vector4(), - - _depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ), - _distanceMaterial = new MeshDistanceMaterial(), - - _materialCache = {}, - - _maxTextureSize = _capabilities.maxTextureSize; - - const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; - - const shadowMaterialVertical = new ShaderMaterial( { - - uniforms: { - shadow_pass: { value: null }, - resolution: { value: new Vector2() }, - radius: { value: 4.0 }, - samples: { value: 8.0 } - }, - - vertexShader: vsm_vert, - - fragmentShader: vsm_frag - - } ); - - const shadowMaterialHorizontal = shadowMaterialVertical.clone(); - shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; - - const fullScreenTri = new BufferGeometry(); - fullScreenTri.setAttribute( - 'position', - new BufferAttribute( - new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ), - 3 - ) - ); - - const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical ); - - const scope = this; - - this.enabled = false; - - this.autoUpdate = true; - this.needsUpdate = false; - - this.type = PCFShadowMap; - - this.render = function ( lights, scene, camera ) { - - if ( scope.enabled === false ) return; - if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; - - if ( lights.length === 0 ) return; - - const currentRenderTarget = _renderer.getRenderTarget(); - const activeCubeFace = _renderer.getActiveCubeFace(); - const activeMipmapLevel = _renderer.getActiveMipmapLevel(); - - const _state = _renderer.state; - - // Set GL state for depth map. - _state.setBlending( NoBlending ); - _state.buffers.color.setClear( 1, 1, 1, 1 ); - _state.buffers.depth.setTest( true ); - _state.setScissorTest( false ); - - // render depth map - - for ( let i = 0, il = lights.length; i < il; i ++ ) { - - const light = lights[ i ]; - const shadow = light.shadow; - - if ( shadow === undefined ) { - - console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); - continue; - - } - - if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue; - - _shadowMapSize.copy( shadow.mapSize ); - - const shadowFrameExtents = shadow.getFrameExtents(); - - _shadowMapSize.multiply( shadowFrameExtents ); - - _viewportSize.copy( shadow.mapSize ); - - if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) { - - if ( _shadowMapSize.x > _maxTextureSize ) { - - _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x ); - _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; - shadow.mapSize.x = _viewportSize.x; - - } - - if ( _shadowMapSize.y > _maxTextureSize ) { - - _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y ); - _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; - shadow.mapSize.y = _viewportSize.y; - - } - - } - - if ( shadow.map === null && ! shadow.isPointLightShadow && this.type === VSMShadowMap ) { - - const pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat }; - - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - shadow.map.texture.name = light.name + '.shadowMap'; - - shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - - shadow.camera.updateProjectionMatrix(); - - } - - if ( shadow.map === null ) { - - const pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; - - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - shadow.map.texture.name = light.name + '.shadowMap'; - - shadow.camera.updateProjectionMatrix(); - - } - - _renderer.setRenderTarget( shadow.map ); - _renderer.clear(); - - const viewportCount = shadow.getViewportCount(); - - for ( let vp = 0; vp < viewportCount; vp ++ ) { - - const viewport = shadow.getViewport( vp ); - - _viewport.set( - _viewportSize.x * viewport.x, - _viewportSize.y * viewport.y, - _viewportSize.x * viewport.z, - _viewportSize.y * viewport.w - ); - - _state.viewport( _viewport ); - - shadow.updateMatrices( light, vp ); - - _frustum = shadow.getFrustum(); - - renderObject( scene, camera, shadow.camera, light, this.type ); - - } - - // do blur pass for VSM - - if ( ! shadow.isPointLightShadow && this.type === VSMShadowMap ) { - - VSMPass( shadow, camera ); - - } - - shadow.needsUpdate = false; - - } - - scope.needsUpdate = false; - - _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); - - }; - - function VSMPass( shadow, camera ) { - - const geometry = _objects.update( fullScreenMesh ); - - // vertical pass - - shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; - shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; - shadowMaterialVertical.uniforms.radius.value = shadow.radius; - shadowMaterialVertical.uniforms.samples.value = shadow.blurSamples; - _renderer.setRenderTarget( shadow.mapPass ); - _renderer.clear(); - _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null ); - - // horizontal pass - - shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; - shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize; - shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; - shadowMaterialHorizontal.uniforms.samples.value = shadow.blurSamples; - _renderer.setRenderTarget( shadow.map ); - _renderer.clear(); - _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null ); - - } - - function getDepthMaterial( object, geometry, material, light, shadowCameraNear, shadowCameraFar, type ) { - - let result = null; - - const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial; - - if ( customMaterial !== undefined ) { - - result = customMaterial; - - } else { - - result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; - - } - - if ( ( _renderer.localClippingEnabled && material.clipShadows === true && material.clippingPlanes.length !== 0 ) || - ( material.displacementMap && material.displacementScale !== 0 ) || - ( material.alphaMap && material.alphaTest > 0 ) ) { - - // in this case we need a unique material instance reflecting the - // appropriate state - - const keyA = result.uuid, keyB = material.uuid; - - let materialsForVariant = _materialCache[ keyA ]; - - if ( materialsForVariant === undefined ) { - - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; - - } - - let cachedMaterial = materialsForVariant[ keyB ]; - - if ( cachedMaterial === undefined ) { - - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; - - } - - result = cachedMaterial; - - } - - result.visible = material.visible; - result.wireframe = material.wireframe; - - if ( type === VSMShadowMap ) { - - result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side; - - } else { - - result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ]; - - } - - result.alphaMap = material.alphaMap; - result.alphaTest = material.alphaTest; - - result.clipShadows = material.clipShadows; - result.clippingPlanes = material.clippingPlanes; - result.clipIntersection = material.clipIntersection; - - result.displacementMap = material.displacementMap; - result.displacementScale = material.displacementScale; - result.displacementBias = material.displacementBias; - - result.wireframeLinewidth = material.wireframeLinewidth; - result.linewidth = material.linewidth; - - if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { - - result.referencePosition.setFromMatrixPosition( light.matrixWorld ); - result.nearDistance = shadowCameraNear; - result.farDistance = shadowCameraFar; - - } - - return result; - - } - - function renderObject( object, camera, shadowCamera, light, type ) { - - if ( object.visible === false ) return; - - const visible = object.layers.test( camera.layers ); - - if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { - - if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { - - object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - - const geometry = _objects.update( object ); - const material = object.material; - - if ( Array.isArray( material ) ) { - - const groups = geometry.groups; - - for ( let k = 0, kl = groups.length; k < kl; k ++ ) { - - const group = groups[ k ]; - const groupMaterial = material[ group.materialIndex ]; - - if ( groupMaterial && groupMaterial.visible ) { - - const depthMaterial = getDepthMaterial( object, geometry, groupMaterial, light, shadowCamera.near, shadowCamera.far, type ); - - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); - - } - - } - - } else if ( material.visible ) { - - const depthMaterial = getDepthMaterial( object, geometry, material, light, shadowCamera.near, shadowCamera.far, type ); - - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); - - } - - } - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - renderObject( children[ i ], camera, shadowCamera, light, type ); - - } - - } - - } - - function WebGLState( gl, extensions, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - function ColorBuffer() { - - let locked = false; - - const color = new Vector4(); - let currentColorMask = null; - const currentColorClear = new Vector4( 0, 0, 0, 0 ); - - return { - - setMask: function ( colorMask ) { - - if ( currentColorMask !== colorMask && ! locked ) { - - gl.colorMask( colorMask, colorMask, colorMask, colorMask ); - currentColorMask = colorMask; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( r, g, b, a, premultipliedAlpha ) { - - if ( premultipliedAlpha === true ) { - - r *= a; g *= a; b *= a; - - } - - color.set( r, g, b, a ); - - if ( currentColorClear.equals( color ) === false ) { - - gl.clearColor( r, g, b, a ); - currentColorClear.copy( color ); - - } - - }, - - reset: function () { - - locked = false; - - currentColorMask = null; - currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state - - } - - }; - - } - - function DepthBuffer() { - - let locked = false; - - let currentDepthMask = null; - let currentDepthFunc = null; - let currentDepthClear = null; - - return { - - setTest: function ( depthTest ) { - - if ( depthTest ) { - - enable( 2929 ); - - } else { - - disable( 2929 ); - - } - - }, - - setMask: function ( depthMask ) { - - if ( currentDepthMask !== depthMask && ! locked ) { - - gl.depthMask( depthMask ); - currentDepthMask = depthMask; - - } - - }, - - setFunc: function ( depthFunc ) { - - if ( currentDepthFunc !== depthFunc ) { - - if ( depthFunc ) { - - switch ( depthFunc ) { - - case NeverDepth: - - gl.depthFunc( 512 ); - break; - - case AlwaysDepth: - - gl.depthFunc( 519 ); - break; - - case LessDepth: - - gl.depthFunc( 513 ); - break; - - case LessEqualDepth: - - gl.depthFunc( 515 ); - break; - - case EqualDepth: - - gl.depthFunc( 514 ); - break; - - case GreaterEqualDepth: - - gl.depthFunc( 518 ); - break; - - case GreaterDepth: - - gl.depthFunc( 516 ); - break; - - case NotEqualDepth: - - gl.depthFunc( 517 ); - break; - - default: - - gl.depthFunc( 515 ); - - } - - } else { - - gl.depthFunc( 515 ); - - } - - currentDepthFunc = depthFunc; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( depth ) { - - if ( currentDepthClear !== depth ) { - - gl.clearDepth( depth ); - currentDepthClear = depth; - - } - - }, - - reset: function () { - - locked = false; - - currentDepthMask = null; - currentDepthFunc = null; - currentDepthClear = null; - - } - - }; - - } - - function StencilBuffer() { - - let locked = false; - - let currentStencilMask = null; - let currentStencilFunc = null; - let currentStencilRef = null; - let currentStencilFuncMask = null; - let currentStencilFail = null; - let currentStencilZFail = null; - let currentStencilZPass = null; - let currentStencilClear = null; - - return { - - setTest: function ( stencilTest ) { - - if ( ! locked ) { - - if ( stencilTest ) { - - enable( 2960 ); - - } else { - - disable( 2960 ); - - } - - } - - }, - - setMask: function ( stencilMask ) { - - if ( currentStencilMask !== stencilMask && ! locked ) { - - gl.stencilMask( stencilMask ); - currentStencilMask = stencilMask; - - } - - }, - - setFunc: function ( stencilFunc, stencilRef, stencilMask ) { - - if ( currentStencilFunc !== stencilFunc || - currentStencilRef !== stencilRef || - currentStencilFuncMask !== stencilMask ) { - - gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); - - currentStencilFunc = stencilFunc; - currentStencilRef = stencilRef; - currentStencilFuncMask = stencilMask; - - } - - }, - - setOp: function ( stencilFail, stencilZFail, stencilZPass ) { - - if ( currentStencilFail !== stencilFail || - currentStencilZFail !== stencilZFail || - currentStencilZPass !== stencilZPass ) { - - gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); - - currentStencilFail = stencilFail; - currentStencilZFail = stencilZFail; - currentStencilZPass = stencilZPass; - - } - - }, - - setLocked: function ( lock ) { - - locked = lock; - - }, - - setClear: function ( stencil ) { - - if ( currentStencilClear !== stencil ) { - - gl.clearStencil( stencil ); - currentStencilClear = stencil; - - } - - }, - - reset: function () { - - locked = false; - - currentStencilMask = null; - currentStencilFunc = null; - currentStencilRef = null; - currentStencilFuncMask = null; - currentStencilFail = null; - currentStencilZFail = null; - currentStencilZPass = null; - currentStencilClear = null; - - } - - }; - - } - - // - - const colorBuffer = new ColorBuffer(); - const depthBuffer = new DepthBuffer(); - const stencilBuffer = new StencilBuffer(); - - let enabledCapabilities = {}; - - let xrFramebuffer = null; - let currentBoundFramebuffers = {}; - - let currentProgram = null; - - let currentBlendingEnabled = false; - let currentBlending = null; - let currentBlendEquation = null; - let currentBlendSrc = null; - let currentBlendDst = null; - let currentBlendEquationAlpha = null; - let currentBlendSrcAlpha = null; - let currentBlendDstAlpha = null; - let currentPremultipledAlpha = false; - - let currentFlipSided = null; - let currentCullFace = null; - - let currentLineWidth = null; - - let currentPolygonOffsetFactor = null; - let currentPolygonOffsetUnits = null; - - const maxTextures = gl.getParameter( 35661 ); - - let lineWidthAvailable = false; - let version = 0; - const glVersion = gl.getParameter( 7938 ); - - if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { - - version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 1.0 ); - - } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) { - - version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 2.0 ); - - } - - let currentTextureSlot = null; - let currentBoundTextures = {}; - - const scissorParam = gl.getParameter( 3088 ); - const viewportParam = gl.getParameter( 2978 ); - - const currentScissor = new Vector4().fromArray( scissorParam ); - const currentViewport = new Vector4().fromArray( viewportParam ); - - function createTexture( type, target, count ) { - - const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. - const texture = gl.createTexture(); - - gl.bindTexture( type, texture ); - gl.texParameteri( type, 10241, 9728 ); - gl.texParameteri( type, 10240, 9728 ); - - for ( let i = 0; i < count; i ++ ) { - - gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); - - } - - return texture; - - } - - const emptyTextures = {}; - emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); - emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); - - // init - - colorBuffer.setClear( 0, 0, 0, 1 ); - depthBuffer.setClear( 1 ); - stencilBuffer.setClear( 0 ); - - enable( 2929 ); - depthBuffer.setFunc( LessEqualDepth ); - - setFlipSided( false ); - setCullFace( CullFaceBack ); - enable( 2884 ); - - setBlending( NoBlending ); - - // - - function enable( id ) { - - if ( enabledCapabilities[ id ] !== true ) { - - gl.enable( id ); - enabledCapabilities[ id ] = true; - - } - - } - - function disable( id ) { - - if ( enabledCapabilities[ id ] !== false ) { - - gl.disable( id ); - enabledCapabilities[ id ] = false; - - } - - } - - function bindXRFramebuffer( framebuffer ) { - - if ( framebuffer !== xrFramebuffer ) { - - gl.bindFramebuffer( 36160, framebuffer ); - - xrFramebuffer = framebuffer; - - } - - } - - function bindFramebuffer( target, framebuffer ) { - - if ( framebuffer === null && xrFramebuffer !== null ) framebuffer = xrFramebuffer; // use active XR framebuffer if available - - if ( currentBoundFramebuffers[ target ] !== framebuffer ) { - - gl.bindFramebuffer( target, framebuffer ); - - currentBoundFramebuffers[ target ] = framebuffer; - - if ( isWebGL2 ) { - - // 36009 is equivalent to 36160 - - if ( target === 36009 ) { - - currentBoundFramebuffers[ 36160 ] = framebuffer; - - } - - if ( target === 36160 ) { - - currentBoundFramebuffers[ 36009 ] = framebuffer; - - } - - } - - return true; - - } - - return false; - - } - - function useProgram( program ) { - - if ( currentProgram !== program ) { - - gl.useProgram( program ); - - currentProgram = program; - - return true; - - } - - return false; - - } - - const equationToGL = { - [ AddEquation ]: 32774, - [ SubtractEquation ]: 32778, - [ ReverseSubtractEquation ]: 32779 - }; - - if ( isWebGL2 ) { - - equationToGL[ MinEquation ] = 32775; - equationToGL[ MaxEquation ] = 32776; - - } else { - - const extension = extensions.get( 'EXT_blend_minmax' ); - - if ( extension !== null ) { - - equationToGL[ MinEquation ] = extension.MIN_EXT; - equationToGL[ MaxEquation ] = extension.MAX_EXT; - - } - - } - - const factorToGL = { - [ ZeroFactor ]: 0, - [ OneFactor ]: 1, - [ SrcColorFactor ]: 768, - [ SrcAlphaFactor ]: 770, - [ SrcAlphaSaturateFactor ]: 776, - [ DstColorFactor ]: 774, - [ DstAlphaFactor ]: 772, - [ OneMinusSrcColorFactor ]: 769, - [ OneMinusSrcAlphaFactor ]: 771, - [ OneMinusDstColorFactor ]: 775, - [ OneMinusDstAlphaFactor ]: 773 - }; - - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { - - if ( blending === NoBlending ) { - - if ( currentBlendingEnabled === true ) { - - disable( 3042 ); - currentBlendingEnabled = false; - - } - - return; - - } - - if ( currentBlendingEnabled === false ) { - - enable( 3042 ); - currentBlendingEnabled = true; - - } - - if ( blending !== CustomBlending ) { - - if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { - - if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { - - gl.blendEquation( 32774 ); - - currentBlendEquation = AddEquation; - currentBlendEquationAlpha = AddEquation; - - } - - if ( premultipliedAlpha ) { - - switch ( blending ) { - - case NormalBlending: - gl.blendFuncSeparate( 1, 771, 1, 771 ); - break; - - case AdditiveBlending: - gl.blendFunc( 1, 1 ); - break; - - case SubtractiveBlending: - gl.blendFuncSeparate( 0, 0, 769, 771 ); - break; - - case MultiplyBlending: - gl.blendFuncSeparate( 0, 768, 0, 770 ); - break; - - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; - - } - - } else { - - switch ( blending ) { - - case NormalBlending: - gl.blendFuncSeparate( 770, 771, 1, 771 ); - break; - - case AdditiveBlending: - gl.blendFunc( 770, 1 ); - break; - - case SubtractiveBlending: - gl.blendFunc( 0, 769 ); - break; - - case MultiplyBlending: - gl.blendFunc( 0, 768 ); - break; - - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; - - } - - } - - currentBlendSrc = null; - currentBlendDst = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; - - currentBlending = blending; - currentPremultipledAlpha = premultipliedAlpha; - - } - - return; - - } - - // custom blending - - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; - - if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - - gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); - - currentBlendEquation = blendEquation; - currentBlendEquationAlpha = blendEquationAlpha; - - } - - if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - - gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); - - currentBlendSrc = blendSrc; - currentBlendDst = blendDst; - currentBlendSrcAlpha = blendSrcAlpha; - currentBlendDstAlpha = blendDstAlpha; - - } - - currentBlending = blending; - currentPremultipledAlpha = null; - - } - - function setMaterial( material, frontFaceCW ) { - - material.side === DoubleSide - ? disable( 2884 ) - : enable( 2884 ); - - let flipSided = ( material.side === BackSide ); - if ( frontFaceCW ) flipSided = ! flipSided; - - setFlipSided( flipSided ); - - ( material.blending === NormalBlending && material.transparent === false ) - ? setBlending( NoBlending ) - : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); - - depthBuffer.setFunc( material.depthFunc ); - depthBuffer.setTest( material.depthTest ); - depthBuffer.setMask( material.depthWrite ); - colorBuffer.setMask( material.colorWrite ); - - const stencilWrite = material.stencilWrite; - stencilBuffer.setTest( stencilWrite ); - if ( stencilWrite ) { - - stencilBuffer.setMask( material.stencilWriteMask ); - stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); - stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); - - } - - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); - - material.alphaToCoverage === true - ? enable( 32926 ) - : disable( 32926 ); - - } - - // - - function setFlipSided( flipSided ) { - - if ( currentFlipSided !== flipSided ) { - - if ( flipSided ) { - - gl.frontFace( 2304 ); - - } else { - - gl.frontFace( 2305 ); - - } - - currentFlipSided = flipSided; - - } - - } - - function setCullFace( cullFace ) { - - if ( cullFace !== CullFaceNone ) { - - enable( 2884 ); - - if ( cullFace !== currentCullFace ) { - - if ( cullFace === CullFaceBack ) { - - gl.cullFace( 1029 ); - - } else if ( cullFace === CullFaceFront ) { - - gl.cullFace( 1028 ); - - } else { - - gl.cullFace( 1032 ); - - } - - } - - } else { - - disable( 2884 ); - - } - - currentCullFace = cullFace; - - } - - function setLineWidth( width ) { - - if ( width !== currentLineWidth ) { - - if ( lineWidthAvailable ) gl.lineWidth( width ); - - currentLineWidth = width; - - } - - } - - function setPolygonOffset( polygonOffset, factor, units ) { - - if ( polygonOffset ) { - - enable( 32823 ); - - if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { - - gl.polygonOffset( factor, units ); - - currentPolygonOffsetFactor = factor; - currentPolygonOffsetUnits = units; - - } - - } else { - - disable( 32823 ); - - } - - } - - function setScissorTest( scissorTest ) { - - if ( scissorTest ) { - - enable( 3089 ); - - } else { - - disable( 3089 ); - - } - - } - - // texture - - function activeTexture( webglSlot ) { - - if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1; - - if ( currentTextureSlot !== webglSlot ) { - - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; - - } - - } - - function bindTexture( webglType, webglTexture ) { - - if ( currentTextureSlot === null ) { - - activeTexture(); - - } - - let boundTexture = currentBoundTextures[ currentTextureSlot ]; - - if ( boundTexture === undefined ) { - - boundTexture = { type: undefined, texture: undefined }; - currentBoundTextures[ currentTextureSlot ] = boundTexture; - - } - - if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { - - gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); - - boundTexture.type = webglType; - boundTexture.texture = webglTexture; - - } - - } - - function unbindTexture() { - - const boundTexture = currentBoundTextures[ currentTextureSlot ]; - - if ( boundTexture !== undefined && boundTexture.type !== undefined ) { - - gl.bindTexture( boundTexture.type, null ); - - boundTexture.type = undefined; - boundTexture.texture = undefined; - - } - - } - - function compressedTexImage2D() { - - try { - - gl.compressedTexImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texImage2D() { - - try { - - gl.texImage2D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - function texImage3D() { - - try { - - gl.texImage3D.apply( gl, arguments ); - - } catch ( error ) { - - console.error( 'THREE.WebGLState:', error ); - - } - - } - - // - - function scissor( scissor ) { - - if ( currentScissor.equals( scissor ) === false ) { - - gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); - currentScissor.copy( scissor ); - - } - - } - - function viewport( viewport ) { - - if ( currentViewport.equals( viewport ) === false ) { - - gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); - currentViewport.copy( viewport ); - - } - - } - - // - - function reset() { - - // reset state - - gl.disable( 3042 ); - gl.disable( 2884 ); - gl.disable( 2929 ); - gl.disable( 32823 ); - gl.disable( 3089 ); - gl.disable( 2960 ); - gl.disable( 32926 ); - - gl.blendEquation( 32774 ); - gl.blendFunc( 1, 0 ); - gl.blendFuncSeparate( 1, 0, 1, 0 ); - - gl.colorMask( true, true, true, true ); - gl.clearColor( 0, 0, 0, 0 ); - - gl.depthMask( true ); - gl.depthFunc( 513 ); - gl.clearDepth( 1 ); - - gl.stencilMask( 0xffffffff ); - gl.stencilFunc( 519, 0, 0xffffffff ); - gl.stencilOp( 7680, 7680, 7680 ); - gl.clearStencil( 0 ); - - gl.cullFace( 1029 ); - gl.frontFace( 2305 ); - - gl.polygonOffset( 0, 0 ); - - gl.activeTexture( 33984 ); - - gl.bindFramebuffer( 36160, null ); - - if ( isWebGL2 === true ) { - - gl.bindFramebuffer( 36009, null ); - gl.bindFramebuffer( 36008, null ); - - } - - gl.useProgram( null ); - - gl.lineWidth( 1 ); - - gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height ); - gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height ); - - // reset internals - - enabledCapabilities = {}; - - currentTextureSlot = null; - currentBoundTextures = {}; - - xrFramebuffer = null; - currentBoundFramebuffers = {}; - - currentProgram = null; - - currentBlendingEnabled = false; - currentBlending = null; - currentBlendEquation = null; - currentBlendSrc = null; - currentBlendDst = null; - currentBlendEquationAlpha = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; - currentPremultipledAlpha = false; - - currentFlipSided = null; - currentCullFace = null; - - currentLineWidth = null; - - currentPolygonOffsetFactor = null; - currentPolygonOffsetUnits = null; - - currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height ); - currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height ); - - colorBuffer.reset(); - depthBuffer.reset(); - stencilBuffer.reset(); - - } - - return { - - buffers: { - color: colorBuffer, - depth: depthBuffer, - stencil: stencilBuffer - }, - - enable: enable, - disable: disable, - - bindFramebuffer: bindFramebuffer, - bindXRFramebuffer: bindXRFramebuffer, - - useProgram: useProgram, - - setBlending: setBlending, - setMaterial: setMaterial, - - setFlipSided: setFlipSided, - setCullFace: setCullFace, - - setLineWidth: setLineWidth, - setPolygonOffset: setPolygonOffset, - - setScissorTest: setScissorTest, - - activeTexture: activeTexture, - bindTexture: bindTexture, - unbindTexture: unbindTexture, - compressedTexImage2D: compressedTexImage2D, - texImage2D: texImage2D, - texImage3D: texImage3D, - - scissor: scissor, - viewport: viewport, - - reset: reset - - }; - - } - - function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { - - const isWebGL2 = capabilities.isWebGL2; - const maxTextures = capabilities.maxTextures; - const maxCubemapSize = capabilities.maxCubemapSize; - const maxTextureSize = capabilities.maxTextureSize; - const maxSamples = capabilities.maxSamples; - - const _videoTextures = new WeakMap(); - let _canvas; - - // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, - // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! - // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). - - let useOffscreenCanvas = false; - - try { - - useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' - && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null; - - } catch ( err ) { - - // Ignore any errors - - } - - function createCanvas( width, height ) { - - // Use OffscreenCanvas when available. Specially needed in web workers - - return useOffscreenCanvas ? - new OffscreenCanvas( width, height ) : - document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - - } - - function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) { - - let scale = 1; - - // handle case if texture exceeds max size - - if ( image.width > maxSize || image.height > maxSize ) { - - scale = maxSize / Math.max( image.width, image.height ); - - } - - // only perform resize if necessary - - if ( scale < 1 || needsPowerOfTwo === true ) { - - // only perform resize for certain image types - - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - - const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor; - - const width = floor( scale * image.width ); - const height = floor( scale * image.height ); - - if ( _canvas === undefined ) _canvas = createCanvas( width, height ); - - // cube textures can't reuse the same canvas - - const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas; - - canvas.width = width; - canvas.height = height; - - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, width, height ); - - console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' ); - - return canvas; - - } else { - - if ( 'data' in image ) { - - console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); - - } - - return image; - - } - - } - - return image; - - } - - function isPowerOfTwo$1( image ) { - - return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ); - - } - - function textureNeedsPowerOfTwo( texture ) { - - if ( isWebGL2 ) return false; - - return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || - ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); - - } - - function textureNeedsGenerateMipmaps( texture, supportsMips ) { - - return texture.generateMipmaps && supportsMips && - texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; - - } - - function generateMipmap( target, texture, width, height, depth = 1 ) { - - _gl.generateMipmap( target ); - - const textureProperties = properties.get( texture ); - - textureProperties.__maxMipLevel = Math.log2( Math.max( width, height, depth ) ); - - } - - function getInternalFormat( internalFormatName, glFormat, glType ) { - - if ( isWebGL2 === false ) return glFormat; - - if ( internalFormatName !== null ) { - - if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ]; - - console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); - - } - - let internalFormat = glFormat; - - if ( glFormat === 6403 ) { - - if ( glType === 5126 ) internalFormat = 33326; - if ( glType === 5131 ) internalFormat = 33325; - if ( glType === 5121 ) internalFormat = 33321; - - } - - if ( glFormat === 6407 ) { - - if ( glType === 5126 ) internalFormat = 34837; - if ( glType === 5131 ) internalFormat = 34843; - if ( glType === 5121 ) internalFormat = 32849; - - } - - if ( glFormat === 6408 ) { - - if ( glType === 5126 ) internalFormat = 34836; - if ( glType === 5131 ) internalFormat = 34842; - if ( glType === 5121 ) internalFormat = 32856; - - } - - if ( internalFormat === 33325 || internalFormat === 33326 || - internalFormat === 34842 || internalFormat === 34836 ) { - - extensions.get( 'EXT_color_buffer_float' ); - - } - - return internalFormat; - - } - - // Fallback filters for non-power-of-2 textures - - function filterFallback( f ) { - - if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - - return 9728; - - } - - return 9729; - - } - - // - - function onTextureDispose( event ) { - - const texture = event.target; - - texture.removeEventListener( 'dispose', onTextureDispose ); - - deallocateTexture( texture ); - - if ( texture.isVideoTexture ) { - - _videoTextures.delete( texture ); - - } - - info.memory.textures --; - - } - - function onRenderTargetDispose( event ) { - - const renderTarget = event.target; - - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - - deallocateRenderTarget( renderTarget ); - - } - - // - - function deallocateTexture( texture ) { - - const textureProperties = properties.get( texture ); - - if ( textureProperties.__webglInit === undefined ) return; - - _gl.deleteTexture( textureProperties.__webglTexture ); - - properties.remove( texture ); - - } - - function deallocateRenderTarget( renderTarget ) { - - const texture = renderTarget.texture; - - const renderTargetProperties = properties.get( renderTarget ); - const textureProperties = properties.get( texture ); - - if ( ! renderTarget ) return; - - if ( textureProperties.__webglTexture !== undefined ) { - - _gl.deleteTexture( textureProperties.__webglTexture ); - - info.memory.textures --; - - } - - if ( renderTarget.depthTexture ) { - - renderTarget.depthTexture.dispose(); - - } - - if ( renderTarget.isWebGLCubeRenderTarget ) { - - for ( let i = 0; i < 6; i ++ ) { - - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); - - } - - } else { - - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); - if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); - if ( renderTargetProperties.__webglColorRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer ); - if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer ); - - } - - if ( renderTarget.isWebGLMultipleRenderTargets ) { - - for ( let i = 0, il = texture.length; i < il; i ++ ) { - - const attachmentProperties = properties.get( texture[ i ] ); - - if ( attachmentProperties.__webglTexture ) { - - _gl.deleteTexture( attachmentProperties.__webglTexture ); - - info.memory.textures --; - - } - - properties.remove( texture[ i ] ); - - } - - } - - properties.remove( texture ); - properties.remove( renderTarget ); - - } - - // - - let textureUnits = 0; - - function resetTextureUnits() { - - textureUnits = 0; - - } - - function allocateTextureUnit() { - - const textureUnit = textureUnits; - - if ( textureUnit >= maxTextures ) { - - console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures ); - - } - - textureUnits += 1; - - return textureUnit; - - } - - // - - function setTexture2D( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.isVideoTexture ) updateVideoTexture( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - const image = texture.image; - - if ( image === undefined ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' ); - - } else if ( image.complete === false ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); - - } else { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - } - - state.activeTexture( 33984 + slot ); - state.bindTexture( 3553, textureProperties.__webglTexture ); - - } - - function setTexture2DArray( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - state.activeTexture( 33984 + slot ); - state.bindTexture( 35866, textureProperties.__webglTexture ); - - } - - function setTexture3D( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadTexture( textureProperties, texture, slot ); - return; - - } - - state.activeTexture( 33984 + slot ); - state.bindTexture( 32879, textureProperties.__webglTexture ); - - } - - function setTextureCube( texture, slot ) { - - const textureProperties = properties.get( texture ); - - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - - uploadCubeTexture( textureProperties, texture, slot ); - return; - - } - - state.activeTexture( 33984 + slot ); - state.bindTexture( 34067, textureProperties.__webglTexture ); - - } - - const wrappingToGL = { - [ RepeatWrapping ]: 10497, - [ ClampToEdgeWrapping ]: 33071, - [ MirroredRepeatWrapping ]: 33648 - }; - - const filterToGL = { - [ NearestFilter ]: 9728, - [ NearestMipmapNearestFilter ]: 9984, - [ NearestMipmapLinearFilter ]: 9986, - - [ LinearFilter ]: 9729, - [ LinearMipmapNearestFilter ]: 9985, - [ LinearMipmapLinearFilter ]: 9987 - }; - - function setTextureParameters( textureType, texture, supportsMips ) { - - if ( supportsMips ) { - - _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] ); - _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] ); - - if ( textureType === 32879 || textureType === 35866 ) { - - _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] ); - - } - - _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] ); - _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] ); - - } else { - - _gl.texParameteri( textureType, 10242, 33071 ); - _gl.texParameteri( textureType, 10243, 33071 ); - - if ( textureType === 32879 || textureType === 35866 ) { - - _gl.texParameteri( textureType, 32882, 33071 ); - - } - - if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { - - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); - - } - - _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); - - if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { - - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); - - } - - } - - if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { - - const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - - if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 - if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only - - if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { - - _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); - properties.get( texture ).__currentAnisotropy = texture.anisotropy; - - } - - } - - } - - function initTexture( textureProperties, texture ) { - - if ( textureProperties.__webglInit === undefined ) { - - textureProperties.__webglInit = true; - - texture.addEventListener( 'dispose', onTextureDispose ); - - textureProperties.__webglTexture = _gl.createTexture(); - - info.memory.textures ++; - - } - - } - - function uploadTexture( textureProperties, texture, slot ) { - - let textureType = 3553; - - if ( texture.isDataTexture2DArray ) textureType = 35866; - if ( texture.isDataTexture3D ) textureType = 32879; - - initTexture( textureProperties, texture ); - - state.activeTexture( 33984 + slot ); - state.bindTexture( textureType, textureProperties.__webglTexture ); - - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); - - const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; - const image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize ); - - const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format ); - - let glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType ); - - setTextureParameters( textureType, texture, supportsMips ); - - let mipmap; - const mipmaps = texture.mipmaps; - - if ( texture.isDepthTexture ) { - - // populate depth texture with dummy data - - glInternalFormat = 6402; - - if ( isWebGL2 ) { - - if ( texture.type === FloatType ) { - - glInternalFormat = 36012; - - } else if ( texture.type === UnsignedIntType ) { - - glInternalFormat = 33190; - - } else if ( texture.type === UnsignedInt248Type ) { - - glInternalFormat = 35056; - - } else { - - glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D - - } - - } else { - - if ( texture.type === FloatType ) { - - console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' ); - - } - - } - - // validation checks for WebGL 1 - - if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { - - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { - - console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); - - texture.type = UnsignedShortType; - glType = utils.convert( texture.type ); - - } - - } - - if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) { - - // Depth stencil textures need the DEPTH_STENCIL internal format - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - glInternalFormat = 34041; - - // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are - // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.type !== UnsignedInt248Type ) { - - console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); - - texture.type = UnsignedInt248Type; - glType = utils.convert( texture.type ); - - } - - } - - // - - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); - - } else if ( texture.isDataTexture ) { - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && supportsMips ) { - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - texture.generateMipmaps = false; - textureProperties.__maxMipLevel = mipmaps.length - 1; - - } else { - - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); - textureProperties.__maxMipLevel = 0; - - } - - } else if ( texture.isCompressedTexture ) { - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - - if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { - - if ( glFormat !== null ) { - - state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } else { - - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); - - } - - } else { - - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - textureProperties.__maxMipLevel = mipmaps.length - 1; - - } else if ( texture.isDataTexture2DArray ) { - - state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); - textureProperties.__maxMipLevel = 0; - - } else if ( texture.isDataTexture3D ) { - - state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); - textureProperties.__maxMipLevel = 0; - - } else { - - // regular Texture (image, video, canvas) - - // use manually created mipmaps if available - // if there are no manual mipmaps - // set 0 level mipmap and then use GL to generate other mipmap levels - - if ( mipmaps.length > 0 && supportsMips ) { - - for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { - - mipmap = mipmaps[ i ]; - state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap ); - - } - - texture.generateMipmaps = false; - textureProperties.__maxMipLevel = mipmaps.length - 1; - - } else { - - state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); - textureProperties.__maxMipLevel = 0; - - } - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( textureType, texture, image.width, image.height ); - - } - - textureProperties.__version = texture.version; - - if ( texture.onUpdate ) texture.onUpdate( texture ); - - } - - function uploadCubeTexture( textureProperties, texture, slot ) { - - if ( texture.image.length !== 6 ) return; - - initTexture( textureProperties, texture ); - - state.activeTexture( 33984 + slot ); - state.bindTexture( 34067, textureProperties.__webglTexture ); - - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); - - const isCompressed = ( texture && ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ) ); - const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); - - const cubeImage = []; - - for ( let i = 0; i < 6; i ++ ) { - - if ( ! isCompressed && ! isDataTexture ) { - - cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize ); - - } else { - - cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - - } - - } - - const image = cubeImage[ 0 ], - supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format ), - glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType ); - - setTextureParameters( 34067, texture, supportsMips ); - - let mipmaps; - - if ( isCompressed ) { - - for ( let i = 0; i < 6; i ++ ) { - - mipmaps = cubeImage[ i ].mipmaps; - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - - if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { - - if ( glFormat !== null ) { - - state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - - } else { - - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); - - } - - } else { - - state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - - } - - } - - } - - textureProperties.__maxMipLevel = mipmaps.length - 1; - - } else { - - mipmaps = texture.mipmaps; - - for ( let i = 0; i < 6; i ++ ) { - - if ( isDataTexture ) { - - state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - const mipmapImage = mipmap.image[ i ].image; - - state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); - - } - - } else { - - state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); - - for ( let j = 0; j < mipmaps.length; j ++ ) { - - const mipmap = mipmaps[ j ]; - - state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); - - } - - } - - } - - textureProperties.__maxMipLevel = mipmaps.length; - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - // We assume images for cube map have the same size. - generateMipmap( 34067, texture, image.width, image.height ); - - } - - textureProperties.__version = texture.version; - - if ( texture.onUpdate ) texture.onUpdate( texture ); - - } - - // Render targets - - // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget ) { - - const glFormat = utils.convert( texture.format ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType ); - - if ( textureTarget === 32879 || textureTarget === 35866 ) { - - state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null ); - - } else { - - state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - - } - - state.bindFramebuffer( 36160, framebuffer ); - _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 ); - state.bindFramebuffer( 36160, null ); - - } - - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer - function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { - - _gl.bindRenderbuffer( 36161, renderbuffer ); - - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - - let glInternalFormat = 33189; - - if ( isMultisample ) { - - const depthTexture = renderTarget.depthTexture; - - if ( depthTexture && depthTexture.isDepthTexture ) { - - if ( depthTexture.type === FloatType ) { - - glInternalFormat = 36012; - - } else if ( depthTexture.type === UnsignedIntType ) { - - glInternalFormat = 33190; - - } - - } - - const samples = getRenderTargetSamples( renderTarget ); - - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); - - } - - _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); - - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - - if ( isMultisample ) { - - const samples = getRenderTargetSamples( renderTarget ); - - _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); - - } - - - _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); - - } else { - - // Use the first texture for MRT so far - const texture = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture[ 0 ] : renderTarget.texture; - - const glFormat = utils.convert( texture.format ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType ); - - if ( isMultisample ) { - - const samples = getRenderTargetSamples( renderTarget ); - - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - } else { - - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); - - } - - } - - _gl.bindRenderbuffer( 36161, null ); - - } - - // Setup resources for a Depth Texture for a FBO (needs an extension) - function setupDepthTexture( framebuffer, renderTarget ) { - - const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); - if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); - - state.bindFramebuffer( 36160, framebuffer ); - - if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { - - throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); - - } - - // upload an empty depth texture with framebuffer size - if ( ! properties.get( renderTarget.depthTexture ).__webglTexture || - renderTarget.depthTexture.image.width !== renderTarget.width || - renderTarget.depthTexture.image.height !== renderTarget.height ) { - - renderTarget.depthTexture.image.width = renderTarget.width; - renderTarget.depthTexture.image.height = renderTarget.height; - renderTarget.depthTexture.needsUpdate = true; - - } - - setTexture2D( renderTarget.depthTexture, 0 ); - - const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; - - if ( renderTarget.depthTexture.format === DepthFormat ) { - - _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); - - } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { - - _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); - - } else { - - throw new Error( 'Unknown depthTexture format' ); - - } - - } - - // Setup GL resources for a non-texture depth buffer - function setupDepthRenderbuffer( renderTarget ) { - - const renderTargetProperties = properties.get( renderTarget ); - - const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - - if ( renderTarget.depthTexture ) { - - if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); - - setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); - - } else { - - if ( isCube ) { - - renderTargetProperties.__webglDepthbuffer = []; - - for ( let i = 0; i < 6; i ++ ) { - - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); - renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); - - } - - } else { - - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); - renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); - - } - - } - - state.bindFramebuffer( 36160, null ); - - } - - // Set up GL resources for the render target - function setupRenderTarget( renderTarget ) { - - const texture = renderTarget.texture; - - const renderTargetProperties = properties.get( renderTarget ); - const textureProperties = properties.get( texture ); - - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - - if ( renderTarget.isWebGLMultipleRenderTargets !== true ) { - - textureProperties.__webglTexture = _gl.createTexture(); - textureProperties.__version = texture.version; - info.memory.textures ++; - - } - - const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); - const isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true ); - const isRenderTarget3D = texture.isDataTexture3D || texture.isDataTexture2DArray; - const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; - - // Handles WebGL2 RGBFormat fallback - #18858 - - if ( isWebGL2 && texture.format === RGBFormat && ( texture.type === FloatType || texture.type === HalfFloatType ) ) { - - texture.format = RGBAFormat; - - console.warn( 'THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.' ); - - } - - // Setup framebuffer - - if ( isCube ) { - - renderTargetProperties.__webglFramebuffer = []; - - for ( let i = 0; i < 6; i ++ ) { - - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); - - } - - } else { - - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); - - if ( isMultipleRenderTargets ) { - - if ( capabilities.drawBuffers ) { - - const textures = renderTarget.texture; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const attachmentProperties = properties.get( textures[ i ] ); - - if ( attachmentProperties.__webglTexture === undefined ) { - - attachmentProperties.__webglTexture = _gl.createTexture(); - - info.memory.textures ++; - - } - - } - - } else { - - console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' ); - - } - - } else if ( isMultisample ) { - - if ( isWebGL2 ) { - - renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); - renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer(); - - _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer ); - - const glFormat = utils.convert( texture.format ); - const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType ); - const samples = getRenderTargetSamples( renderTarget ); - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer ); - _gl.bindRenderbuffer( 36161, null ); - - if ( renderTarget.depthBuffer ) { - - renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true ); - - } - - state.bindFramebuffer( 36160, null ); - - - } else { - - console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' ); - - } - - } - - } - - // Setup color buffer - - if ( isCube ) { - - state.bindTexture( 34067, textureProperties.__webglTexture ); - setTextureParameters( 34067, texture, supportsMips ); - - for ( let i = 0; i < 6; i ++ ) { - - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, 36064, 34069 + i ); - - } - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( 34067, texture, renderTarget.width, renderTarget.height ); - - } - - state.unbindTexture(); - - } else if ( isMultipleRenderTargets ) { - - const textures = renderTarget.texture; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const attachment = textures[ i ]; - const attachmentProperties = properties.get( attachment ); - - state.bindTexture( 3553, attachmentProperties.__webglTexture ); - setTextureParameters( 3553, attachment, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, 36064 + i, 3553 ); - - if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { - - generateMipmap( 3553, attachment, renderTarget.width, renderTarget.height ); - - } - - } - - state.unbindTexture(); - - } else { - - let glTextureType = 3553; - - if ( isRenderTarget3D ) { - - // Render targets containing layers, i.e: Texture 3D and 2d arrays - - if ( isWebGL2 ) { - - const isTexture3D = texture.isDataTexture3D; - glTextureType = isTexture3D ? 32879 : 35866; - - } else { - - console.warn( 'THREE.DataTexture3D and THREE.DataTexture2DArray only supported with WebGL2.' ); - - } - - } - - state.bindTexture( glTextureType, textureProperties.__webglTexture ); - setTextureParameters( glTextureType, texture, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, 36064, glTextureType ); - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - generateMipmap( glTextureType, texture, renderTarget.width, renderTarget.height, renderTarget.depth ); - - } - - state.unbindTexture(); - - } - - // Setup depth and stencil buffers - - if ( renderTarget.depthBuffer ) { - - setupDepthRenderbuffer( renderTarget ); - - } - - } - - function updateRenderTargetMipmap( renderTarget ) { - - const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; - - const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - const texture = textures[ i ]; - - if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - - const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553; - const webglTexture = properties.get( texture ).__webglTexture; - - state.bindTexture( target, webglTexture ); - generateMipmap( target, texture, renderTarget.width, renderTarget.height ); - state.unbindTexture(); - - } - - } - - } - - function updateMultisampleRenderTarget( renderTarget ) { - - if ( renderTarget.isWebGLMultisampleRenderTarget ) { - - if ( isWebGL2 ) { - - const width = renderTarget.width; - const height = renderTarget.height; - let mask = 16384; - - if ( renderTarget.depthBuffer ) mask |= 256; - if ( renderTarget.stencilBuffer ) mask |= 1024; - - const renderTargetProperties = properties.get( renderTarget ); - - state.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer ); - state.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer ); - - _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 ); - - state.bindFramebuffer( 36008, null ); - state.bindFramebuffer( 36009, renderTargetProperties.__webglMultisampledFramebuffer ); - - } else { - - console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' ); - - } - - } - - } - - function getRenderTargetSamples( renderTarget ) { - - return ( isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ? - Math.min( maxSamples, renderTarget.samples ) : 0; - - } - - function updateVideoTexture( texture ) { - - const frame = info.render.frame; - - // Check the last frame we updated the VideoTexture - - if ( _videoTextures.get( texture ) !== frame ) { - - _videoTextures.set( texture, frame ); - texture.update(); - - } - - } - - // backwards compatibility - - let warnedTexture2D = false; - let warnedTextureCube = false; - - function safeSetTexture2D( texture, slot ) { - - if ( texture && texture.isWebGLRenderTarget ) { - - if ( warnedTexture2D === false ) { - - console.warn( 'THREE.WebGLTextures.safeSetTexture2D: don\'t use render targets as textures. Use their .texture property instead.' ); - warnedTexture2D = true; - - } - - texture = texture.texture; - - } - - setTexture2D( texture, slot ); - - } - - function safeSetTextureCube( texture, slot ) { - - if ( texture && texture.isWebGLCubeRenderTarget ) { - - if ( warnedTextureCube === false ) { - - console.warn( 'THREE.WebGLTextures.safeSetTextureCube: don\'t use cube render targets as textures. Use their .texture property instead.' ); - warnedTextureCube = true; - - } - - texture = texture.texture; - - } - - - setTextureCube( texture, slot ); - - } - - // - - this.allocateTextureUnit = allocateTextureUnit; - this.resetTextureUnits = resetTextureUnits; - - this.setTexture2D = setTexture2D; - this.setTexture2DArray = setTexture2DArray; - this.setTexture3D = setTexture3D; - this.setTextureCube = setTextureCube; - this.setupRenderTarget = setupRenderTarget; - this.updateRenderTargetMipmap = updateRenderTargetMipmap; - this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; - - this.safeSetTexture2D = safeSetTexture2D; - this.safeSetTextureCube = safeSetTextureCube; - - } - - function WebGLUtils( gl, extensions, capabilities ) { - - const isWebGL2 = capabilities.isWebGL2; - - function convert( p ) { - - let extension; - - if ( p === UnsignedByteType ) return 5121; - if ( p === UnsignedShort4444Type ) return 32819; - if ( p === UnsignedShort5551Type ) return 32820; - if ( p === UnsignedShort565Type ) return 33635; - - if ( p === ByteType ) return 5120; - if ( p === ShortType ) return 5122; - if ( p === UnsignedShortType ) return 5123; - if ( p === IntType ) return 5124; - if ( p === UnsignedIntType ) return 5125; - if ( p === FloatType ) return 5126; - - if ( p === HalfFloatType ) { - - if ( isWebGL2 ) return 5131; - - extension = extensions.get( 'OES_texture_half_float' ); - - if ( extension !== null ) { - - return extension.HALF_FLOAT_OES; - - } else { - - return null; - - } - - } - - if ( p === AlphaFormat ) return 6406; - if ( p === RGBFormat ) return 6407; - if ( p === RGBAFormat ) return 6408; - if ( p === LuminanceFormat ) return 6409; - if ( p === LuminanceAlphaFormat ) return 6410; - if ( p === DepthFormat ) return 6402; - if ( p === DepthStencilFormat ) return 34041; - if ( p === RedFormat ) return 6403; - - // WebGL2 formats. - - if ( p === RedIntegerFormat ) return 36244; - if ( p === RGFormat ) return 33319; - if ( p === RGIntegerFormat ) return 33320; - if ( p === RGBIntegerFormat ) return 36248; - if ( p === RGBAIntegerFormat ) return 36249; - - if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || - p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); - - if ( extension !== null ) { - - if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; - - } else { - - return null; - - } - - } - - if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || - p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - - if ( extension !== null ) { - - if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - - } else { - - return null; - - } - - } - - if ( p === RGB_ETC1_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); - - if ( extension !== null ) { - - return extension.COMPRESSED_RGB_ETC1_WEBGL; - - } else { - - return null; - - } - - } - - if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_etc' ); - - if ( extension !== null ) { - - if ( p === RGB_ETC2_Format ) return extension.COMPRESSED_RGB8_ETC2; - if ( p === RGBA_ETC2_EAC_Format ) return extension.COMPRESSED_RGBA8_ETC2_EAC; - - } - - } - - if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || - p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || - p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || - p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || - p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format || - p === SRGB8_ALPHA8_ASTC_4x4_Format || p === SRGB8_ALPHA8_ASTC_5x4_Format || p === SRGB8_ALPHA8_ASTC_5x5_Format || - p === SRGB8_ALPHA8_ASTC_6x5_Format || p === SRGB8_ALPHA8_ASTC_6x6_Format || p === SRGB8_ALPHA8_ASTC_8x5_Format || - p === SRGB8_ALPHA8_ASTC_8x6_Format || p === SRGB8_ALPHA8_ASTC_8x8_Format || p === SRGB8_ALPHA8_ASTC_10x5_Format || - p === SRGB8_ALPHA8_ASTC_10x6_Format || p === SRGB8_ALPHA8_ASTC_10x8_Format || p === SRGB8_ALPHA8_ASTC_10x10_Format || - p === SRGB8_ALPHA8_ASTC_12x10_Format || p === SRGB8_ALPHA8_ASTC_12x12_Format ) { - - extension = extensions.get( 'WEBGL_compressed_texture_astc' ); - - if ( extension !== null ) { - - // TODO Complete? - - return p; - - } else { - - return null; - - } - - } - - if ( p === RGBA_BPTC_Format ) { - - extension = extensions.get( 'EXT_texture_compression_bptc' ); - - if ( extension !== null ) { - - // TODO Complete? - - return p; - - } else { - - return null; - - } - - } - - if ( p === UnsignedInt248Type ) { - - if ( isWebGL2 ) return 34042; - - extension = extensions.get( 'WEBGL_depth_texture' ); - - if ( extension !== null ) { - - return extension.UNSIGNED_INT_24_8_WEBGL; - - } else { - - return null; - - } - - } - - } - - return { convert: convert }; - - } - - class ArrayCamera extends PerspectiveCamera { - - constructor( array = [] ) { - - super(); - - this.cameras = array; - - } - - } - - ArrayCamera.prototype.isArrayCamera = true; - - class Group extends Object3D { - - constructor() { - - super(); - - this.type = 'Group'; - - } - - } - - Group.prototype.isGroup = true; - - const _moveEvent = { type: 'move' }; - - class WebXRController { - - constructor() { - - this._targetRay = null; - this._grip = null; - this._hand = null; - - } - - getHandSpace() { - - if ( this._hand === null ) { - - this._hand = new Group(); - this._hand.matrixAutoUpdate = false; - this._hand.visible = false; - - this._hand.joints = {}; - this._hand.inputState = { pinching: false }; - - } - - return this._hand; - - } - - getTargetRaySpace() { - - if ( this._targetRay === null ) { - - this._targetRay = new Group(); - this._targetRay.matrixAutoUpdate = false; - this._targetRay.visible = false; - this._targetRay.hasLinearVelocity = false; - this._targetRay.linearVelocity = new Vector3(); - this._targetRay.hasAngularVelocity = false; - this._targetRay.angularVelocity = new Vector3(); - - } - - return this._targetRay; - - } - - getGripSpace() { - - if ( this._grip === null ) { - - this._grip = new Group(); - this._grip.matrixAutoUpdate = false; - this._grip.visible = false; - this._grip.hasLinearVelocity = false; - this._grip.linearVelocity = new Vector3(); - this._grip.hasAngularVelocity = false; - this._grip.angularVelocity = new Vector3(); - - } - - return this._grip; - - } - - dispatchEvent( event ) { - - if ( this._targetRay !== null ) { - - this._targetRay.dispatchEvent( event ); - - } - - if ( this._grip !== null ) { - - this._grip.dispatchEvent( event ); - - } - - if ( this._hand !== null ) { - - this._hand.dispatchEvent( event ); - - } - - return this; - - } - - disconnect( inputSource ) { - - this.dispatchEvent( { type: 'disconnected', data: inputSource } ); - - if ( this._targetRay !== null ) { - - this._targetRay.visible = false; - - } - - if ( this._grip !== null ) { - - this._grip.visible = false; - - } - - if ( this._hand !== null ) { - - this._hand.visible = false; - - } - - return this; - - } - - update( inputSource, frame, referenceSpace ) { - - let inputPose = null; - let gripPose = null; - let handPose = null; - - const targetRay = this._targetRay; - const grip = this._grip; - const hand = this._hand; - - if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) { - - if ( targetRay !== null ) { - - inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace ); - - if ( inputPose !== null ) { - - targetRay.matrix.fromArray( inputPose.transform.matrix ); - targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); - - if ( inputPose.linearVelocity ) { - - targetRay.hasLinearVelocity = true; - targetRay.linearVelocity.copy( inputPose.linearVelocity ); - - } else { - - targetRay.hasLinearVelocity = false; - - } - - if ( inputPose.angularVelocity ) { - - targetRay.hasAngularVelocity = true; - targetRay.angularVelocity.copy( inputPose.angularVelocity ); - - } else { - - targetRay.hasAngularVelocity = false; - - } - - this.dispatchEvent( _moveEvent ); - - } - - } - - if ( hand && inputSource.hand ) { - - handPose = true; - - for ( const inputjoint of inputSource.hand.values() ) { - - // Update the joints groups with the XRJoint poses - const jointPose = frame.getJointPose( inputjoint, referenceSpace ); - - if ( hand.joints[ inputjoint.jointName ] === undefined ) { - - // The transform of this joint will be updated with the joint pose on each frame - const joint = new Group(); - joint.matrixAutoUpdate = false; - joint.visible = false; - hand.joints[ inputjoint.jointName ] = joint; - // ?? - hand.add( joint ); - - } - - const joint = hand.joints[ inputjoint.jointName ]; - - if ( jointPose !== null ) { - - joint.matrix.fromArray( jointPose.transform.matrix ); - joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); - joint.jointRadius = jointPose.radius; - - } - - joint.visible = jointPose !== null; - - } - - // Custom events - - // Check pinchz - const indexTip = hand.joints[ 'index-finger-tip' ]; - const thumbTip = hand.joints[ 'thumb-tip' ]; - const distance = indexTip.position.distanceTo( thumbTip.position ); - - const distanceToPinch = 0.02; - const threshold = 0.005; - - if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) { - - hand.inputState.pinching = false; - this.dispatchEvent( { - type: 'pinchend', - handedness: inputSource.handedness, - target: this - } ); - - } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) { - - hand.inputState.pinching = true; - this.dispatchEvent( { - type: 'pinchstart', - handedness: inputSource.handedness, - target: this - } ); - - } - - } else { - - if ( grip !== null && inputSource.gripSpace ) { - - gripPose = frame.getPose( inputSource.gripSpace, referenceSpace ); - - if ( gripPose !== null ) { - - grip.matrix.fromArray( gripPose.transform.matrix ); - grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); - - if ( gripPose.linearVelocity ) { - - grip.hasLinearVelocity = true; - grip.linearVelocity.copy( gripPose.linearVelocity ); - - } else { - - grip.hasLinearVelocity = false; - - } - - if ( gripPose.angularVelocity ) { - - grip.hasAngularVelocity = true; - grip.angularVelocity.copy( gripPose.angularVelocity ); - - } else { - - grip.hasAngularVelocity = false; - - } - - } - - } - - } - - } - - if ( targetRay !== null ) { - - targetRay.visible = ( inputPose !== null ); - - } - - if ( grip !== null ) { - - grip.visible = ( gripPose !== null ); - - } - - if ( hand !== null ) { - - hand.visible = ( handPose !== null ); - - } - - return this; - - } - - } - - class WebXRManager extends EventDispatcher { - - constructor( renderer, gl ) { - - super(); - - const scope = this; - const state = renderer.state; - - let session = null; - let framebufferScaleFactor = 1.0; - - let referenceSpace = null; - let referenceSpaceType = 'local-floor'; - - let pose = null; - let glBinding = null; - let glFramebuffer = null; - let glProjLayer = null; - let glBaseLayer = null; - let isMultisample = false; - let glMultisampledFramebuffer = null; - let glColorRenderbuffer = null; - let glDepthRenderbuffer = null; - let xrFrame = null; - let depthStyle = null; - let clearStyle = null; - - const controllers = []; - const inputSourcesMap = new Map(); - - // - - const cameraL = new PerspectiveCamera(); - cameraL.layers.enable( 1 ); - cameraL.viewport = new Vector4(); - - const cameraR = new PerspectiveCamera(); - cameraR.layers.enable( 2 ); - cameraR.viewport = new Vector4(); - - const cameras = [ cameraL, cameraR ]; - - const cameraVR = new ArrayCamera(); - cameraVR.layers.enable( 1 ); - cameraVR.layers.enable( 2 ); - - let _currentDepthNear = null; - let _currentDepthFar = null; - - // - - this.cameraAutoUpdate = true; - this.enabled = false; - - this.isPresenting = false; - - this.getController = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getTargetRaySpace(); - - }; - - this.getControllerGrip = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getGripSpace(); - - }; - - this.getHand = function ( index ) { - - let controller = controllers[ index ]; - - if ( controller === undefined ) { - - controller = new WebXRController(); - controllers[ index ] = controller; - - } - - return controller.getHandSpace(); - - }; - - // - - function onSessionEvent( event ) { - - const controller = inputSourcesMap.get( event.inputSource ); - - if ( controller ) { - - controller.dispatchEvent( { type: event.type, data: event.inputSource } ); - - } - - } - - function onSessionEnd() { - - inputSourcesMap.forEach( function ( controller, inputSource ) { - - controller.disconnect( inputSource ); - - } ); - - inputSourcesMap.clear(); - - _currentDepthNear = null; - _currentDepthFar = null; - - // restore framebuffer/rendering state - - state.bindXRFramebuffer( null ); - renderer.setRenderTarget( renderer.getRenderTarget() ); - - if ( glFramebuffer ) gl.deleteFramebuffer( glFramebuffer ); - if ( glMultisampledFramebuffer ) gl.deleteFramebuffer( glMultisampledFramebuffer ); - if ( glColorRenderbuffer ) gl.deleteRenderbuffer( glColorRenderbuffer ); - if ( glDepthRenderbuffer ) gl.deleteRenderbuffer( glDepthRenderbuffer ); - glFramebuffer = null; - glMultisampledFramebuffer = null; - glColorRenderbuffer = null; - glDepthRenderbuffer = null; - glBaseLayer = null; - glProjLayer = null; - glBinding = null; - session = null; - - // - - animation.stop(); - - scope.isPresenting = false; - - scope.dispatchEvent( { type: 'sessionend' } ); - - } - - this.setFramebufferScaleFactor = function ( value ) { - - framebufferScaleFactor = value; - - if ( scope.isPresenting === true ) { - - console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' ); - - } - - }; - - this.setReferenceSpaceType = function ( value ) { - - referenceSpaceType = value; - - if ( scope.isPresenting === true ) { - - console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' ); - - } - - }; - - this.getReferenceSpace = function () { - - return referenceSpace; - - }; - - this.getBaseLayer = function () { - - return glProjLayer !== null ? glProjLayer : glBaseLayer; - - }; - - this.getBinding = function () { - - return glBinding; - - }; - - this.getFrame = function () { - - return xrFrame; - - }; - - this.getSession = function () { - - return session; - - }; - - this.setSession = async function ( value ) { - - session = value; - - if ( session !== null ) { - - session.addEventListener( 'select', onSessionEvent ); - session.addEventListener( 'selectstart', onSessionEvent ); - session.addEventListener( 'selectend', onSessionEvent ); - session.addEventListener( 'squeeze', onSessionEvent ); - session.addEventListener( 'squeezestart', onSessionEvent ); - session.addEventListener( 'squeezeend', onSessionEvent ); - session.addEventListener( 'end', onSessionEnd ); - session.addEventListener( 'inputsourceschange', onInputSourcesChange ); - - const attributes = gl.getContextAttributes(); - - if ( attributes.xrCompatible !== true ) { - - await gl.makeXRCompatible(); - - } - - if ( session.renderState.layers === undefined ) { - - const layerInit = { - antialias: attributes.antialias, - alpha: attributes.alpha, - depth: attributes.depth, - stencil: attributes.stencil, - framebufferScaleFactor: framebufferScaleFactor - }; - - glBaseLayer = new XRWebGLLayer( session, gl, layerInit ); - - session.updateRenderState( { baseLayer: glBaseLayer } ); - - } else if ( gl instanceof WebGLRenderingContext ) { - - // Use old style webgl layer because we can't use MSAA - // WebGL2 support. - - const layerInit = { - antialias: true, - alpha: attributes.alpha, - depth: attributes.depth, - stencil: attributes.stencil, - framebufferScaleFactor: framebufferScaleFactor - }; - - glBaseLayer = new XRWebGLLayer( session, gl, layerInit ); - - session.updateRenderState( { layers: [ glBaseLayer ] } ); - - } else { - - isMultisample = attributes.antialias; - let depthFormat = null; - - - if ( attributes.depth ) { - - clearStyle = 256; - - if ( attributes.stencil ) clearStyle |= 1024; - - depthStyle = attributes.stencil ? 33306 : 36096; - depthFormat = attributes.stencil ? 35056 : 33190; - - } - - const projectionlayerInit = { - colorFormat: attributes.alpha ? 32856 : 32849, - depthFormat: depthFormat, - scaleFactor: framebufferScaleFactor - }; - - glBinding = new XRWebGLBinding( session, gl ); - - glProjLayer = glBinding.createProjectionLayer( projectionlayerInit ); - - glFramebuffer = gl.createFramebuffer(); - - session.updateRenderState( { layers: [ glProjLayer ] } ); - - if ( isMultisample ) { - - glMultisampledFramebuffer = gl.createFramebuffer(); - glColorRenderbuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer( 36161, glColorRenderbuffer ); - gl.renderbufferStorageMultisample( - 36161, - 4, - 32856, - glProjLayer.textureWidth, - glProjLayer.textureHeight ); - state.bindFramebuffer( 36160, glMultisampledFramebuffer ); - gl.framebufferRenderbuffer( 36160, 36064, 36161, glColorRenderbuffer ); - gl.bindRenderbuffer( 36161, null ); - - if ( depthFormat !== null ) { - - glDepthRenderbuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer( 36161, glDepthRenderbuffer ); - gl.renderbufferStorageMultisample( 36161, 4, depthFormat, glProjLayer.textureWidth, glProjLayer.textureHeight ); - gl.framebufferRenderbuffer( 36160, depthStyle, 36161, glDepthRenderbuffer ); - gl.bindRenderbuffer( 36161, null ); - - } - - state.bindFramebuffer( 36160, null ); - - } - - } - - referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); - - animation.setContext( session ); - animation.start(); - - scope.isPresenting = true; - - scope.dispatchEvent( { type: 'sessionstart' } ); - - } - - }; - - function onInputSourcesChange( event ) { - - const inputSources = session.inputSources; - - // Assign inputSources to available controllers - - for ( let i = 0; i < controllers.length; i ++ ) { - - inputSourcesMap.set( inputSources[ i ], controllers[ i ] ); - - } - - // Notify disconnected - - for ( let i = 0; i < event.removed.length; i ++ ) { - - const inputSource = event.removed[ i ]; - const controller = inputSourcesMap.get( inputSource ); - - if ( controller ) { - - controller.dispatchEvent( { type: 'disconnected', data: inputSource } ); - inputSourcesMap.delete( inputSource ); - - } - - } - - // Notify connected - - for ( let i = 0; i < event.added.length; i ++ ) { - - const inputSource = event.added[ i ]; - const controller = inputSourcesMap.get( inputSource ); - - if ( controller ) { - - controller.dispatchEvent( { type: 'connected', data: inputSource } ); - - } - - } - - } - - // - - const cameraLPos = new Vector3(); - const cameraRPos = new Vector3(); - - /** - * Assumes 2 cameras that are parallel and share an X-axis, and that - * the cameras' projection and world matrices have already been set. - * And that near and far planes are identical for both cameras. - * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 - */ - function setProjectionFromUnion( camera, cameraL, cameraR ) { - - cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); - cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); - - const ipd = cameraLPos.distanceTo( cameraRPos ); - - const projL = cameraL.projectionMatrix.elements; - const projR = cameraR.projectionMatrix.elements; - - // VR systems will have identical far and near planes, and - // most likely identical top and bottom frustum extents. - // Use the left camera for these values. - const near = projL[ 14 ] / ( projL[ 10 ] - 1 ); - const far = projL[ 14 ] / ( projL[ 10 ] + 1 ); - const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; - const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; - - const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; - const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; - const left = near * leftFov; - const right = near * rightFov; - - // Calculate the new camera's position offset from the - // left camera. xOffset should be roughly half `ipd`. - const zOffset = ipd / ( - leftFov + rightFov ); - const xOffset = zOffset * - leftFov; - - // TODO: Better way to apply this offset? - cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale ); - camera.translateX( xOffset ); - camera.translateZ( zOffset ); - camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale ); - camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); - - // Find the union of the frustum values of the cameras and scale - // the values so that the near plane's position does not change in world space, - // although must now be relative to the new union camera. - const near2 = near + zOffset; - const far2 = far + zOffset; - const left2 = left - xOffset; - const right2 = right + ( ipd - xOffset ); - const top2 = topFov * far / far2 * near2; - const bottom2 = bottomFov * far / far2 * near2; - - camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); - - } - - function updateCamera( camera, parent ) { - - if ( parent === null ) { - - camera.matrixWorld.copy( camera.matrix ); - - } else { - - camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); - - } - - camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); - - } - - this.updateCamera = function ( camera ) { - - if ( session === null ) return; - - cameraVR.near = cameraR.near = cameraL.near = camera.near; - cameraVR.far = cameraR.far = cameraL.far = camera.far; - - if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) { - - // Note that the new renderState won't apply until the next frame. See #18320 - - session.updateRenderState( { - depthNear: cameraVR.near, - depthFar: cameraVR.far - } ); - - _currentDepthNear = cameraVR.near; - _currentDepthFar = cameraVR.far; - - } - - const parent = camera.parent; - const cameras = cameraVR.cameras; - - updateCamera( cameraVR, parent ); - - for ( let i = 0; i < cameras.length; i ++ ) { - - updateCamera( cameras[ i ], parent ); - - } - - cameraVR.matrixWorld.decompose( cameraVR.position, cameraVR.quaternion, cameraVR.scale ); - - // update user camera and its children - - camera.position.copy( cameraVR.position ); - camera.quaternion.copy( cameraVR.quaternion ); - camera.scale.copy( cameraVR.scale ); - camera.matrix.copy( cameraVR.matrix ); - camera.matrixWorld.copy( cameraVR.matrixWorld ); - - const children = camera.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - children[ i ].updateMatrixWorld( true ); - - } - - // update projection matrix for proper view frustum culling - - if ( cameras.length === 2 ) { - - setProjectionFromUnion( cameraVR, cameraL, cameraR ); - - } else { - - // assume single camera setup (AR) - - cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); - - } - - }; - - this.getCamera = function () { - - return cameraVR; - - }; - - this.getFoveation = function () { - - if ( glProjLayer !== null ) { - - return glProjLayer.fixedFoveation; - - } - - if ( glBaseLayer !== null ) { - - return glBaseLayer.fixedFoveation; - - } - - return undefined; - - }; - - this.setFoveation = function ( foveation ) { - - // 0 = no foveation = full resolution - // 1 = maximum foveation = the edges render at lower resolution - - if ( glProjLayer !== null ) { - - glProjLayer.fixedFoveation = foveation; - - } - - if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { - - glBaseLayer.fixedFoveation = foveation; - - } - - }; - - // Animation Loop - - let onAnimationFrameCallback = null; - - function onAnimationFrame( time, frame ) { - - pose = frame.getViewerPose( referenceSpace ); - xrFrame = frame; - - if ( pose !== null ) { - - const views = pose.views; - - if ( glBaseLayer !== null ) { - - state.bindXRFramebuffer( glBaseLayer.framebuffer ); - - } - - let cameraVRNeedsUpdate = false; - - // check if it's necessary to rebuild cameraVR's camera list - - if ( views.length !== cameraVR.cameras.length ) { - - cameraVR.cameras.length = 0; - - cameraVRNeedsUpdate = true; - - } - - for ( let i = 0; i < views.length; i ++ ) { - - const view = views[ i ]; - - let viewport = null; - - if ( glBaseLayer !== null ) { - - viewport = glBaseLayer.getViewport( view ); - - } else { - - const glSubImage = glBinding.getViewSubImage( glProjLayer, view ); - - state.bindXRFramebuffer( glFramebuffer ); - - if ( glSubImage.depthStencilTexture !== undefined ) { - - gl.framebufferTexture2D( 36160, depthStyle, 3553, glSubImage.depthStencilTexture, 0 ); - - } - - gl.framebufferTexture2D( 36160, 36064, 3553, glSubImage.colorTexture, 0 ); - - viewport = glSubImage.viewport; - - } - - const camera = cameras[ i ]; - - camera.matrix.fromArray( view.transform.matrix ); - camera.projectionMatrix.fromArray( view.projectionMatrix ); - camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); - - if ( i === 0 ) { - - cameraVR.matrix.copy( camera.matrix ); - - } - - if ( cameraVRNeedsUpdate === true ) { - - cameraVR.cameras.push( camera ); - - } - - } - - if ( isMultisample ) { - - state.bindXRFramebuffer( glMultisampledFramebuffer ); - - if ( clearStyle !== null ) gl.clear( clearStyle ); - - } - - } - - // - - const inputSources = session.inputSources; - - for ( let i = 0; i < controllers.length; i ++ ) { - - const controller = controllers[ i ]; - const inputSource = inputSources[ i ]; - - controller.update( inputSource, frame, referenceSpace ); - - } - - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame ); - - if ( isMultisample ) { - - const width = glProjLayer.textureWidth; - const height = glProjLayer.textureHeight; - - state.bindFramebuffer( 36008, glMultisampledFramebuffer ); - state.bindFramebuffer( 36009, glFramebuffer ); - // Invalidate the depth here to avoid flush of the depth data to main memory. - gl.invalidateFramebuffer( 36008, [ depthStyle ] ); - gl.invalidateFramebuffer( 36009, [ depthStyle ] ); - gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, 16384, 9728 ); - // Invalidate the MSAA buffer because it's not needed anymore. - gl.invalidateFramebuffer( 36008, [ 36064 ] ); - state.bindFramebuffer( 36008, null ); - state.bindFramebuffer( 36009, null ); - - state.bindFramebuffer( 36160, glMultisampledFramebuffer ); - - } - - xrFrame = null; - - } - - const animation = new WebGLAnimation(); - - animation.setAnimationLoop( onAnimationFrame ); - - this.setAnimationLoop = function ( callback ) { - - onAnimationFrameCallback = callback; - - }; - - this.dispose = function () {}; - - } - - } - - function WebGLMaterials( properties ) { - - function refreshFogUniforms( uniforms, fog ) { - - uniforms.fogColor.value.copy( fog.color ); - - if ( fog.isFog ) { - - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; - - } else if ( fog.isFogExp2 ) { - - uniforms.fogDensity.value = fog.density; - - } - - } - - function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) { - - if ( material.isMeshBasicMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - } else if ( material.isMeshLambertMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsLambert( uniforms, material ); - - } else if ( material.isMeshToonMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsToon( uniforms, material ); - - } else if ( material.isMeshPhongMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsPhong( uniforms, material ); - - } else if ( material.isMeshStandardMaterial ) { - - refreshUniformsCommon( uniforms, material ); - - if ( material.isMeshPhysicalMaterial ) { - - refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ); - - } else { - - refreshUniformsStandard( uniforms, material ); - - } - - } else if ( material.isMeshMatcapMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsMatcap( uniforms, material ); - - } else if ( material.isMeshDepthMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsDepth( uniforms, material ); - - } else if ( material.isMeshDistanceMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsDistance( uniforms, material ); - - } else if ( material.isMeshNormalMaterial ) { - - refreshUniformsCommon( uniforms, material ); - refreshUniformsNormal( uniforms, material ); - - } else if ( material.isLineBasicMaterial ) { - - refreshUniformsLine( uniforms, material ); - - if ( material.isLineDashedMaterial ) { - - refreshUniformsDash( uniforms, material ); - - } - - } else if ( material.isPointsMaterial ) { - - refreshUniformsPoints( uniforms, material, pixelRatio, height ); - - } else if ( material.isSpriteMaterial ) { - - refreshUniformsSprites( uniforms, material ); - - } else if ( material.isShadowMaterial ) { - - uniforms.color.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - } else if ( material.isShaderMaterial ) { - - material.uniformsNeedUpdate = false; // #15581 - - } - - } - - function refreshUniformsCommon( uniforms, material ) { - - uniforms.opacity.value = material.opacity; - - if ( material.color ) { - - uniforms.diffuse.value.copy( material.color ); - - } - - if ( material.emissive ) { - - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - - } - - if ( material.map ) { - - uniforms.map.value = material.map; - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - } - - if ( material.specularMap ) { - - uniforms.specularMap.value = material.specularMap; - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - const envMap = properties.get( material ).envMap; - - if ( envMap ) { - - uniforms.envMap.value = envMap; - - uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - - uniforms.reflectivity.value = material.reflectivity; - uniforms.ior.value = material.ior; - uniforms.refractionRatio.value = material.refractionRatio; - - const maxMipLevel = properties.get( envMap ).__maxMipLevel; - - if ( maxMipLevel !== undefined ) { - - uniforms.maxMipLevel.value = maxMipLevel; - - } - - } - - if ( material.lightMap ) { - - uniforms.lightMap.value = material.lightMap; - uniforms.lightMapIntensity.value = material.lightMapIntensity; - - } - - if ( material.aoMap ) { - - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; - - } - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. displacementMap map - // 4. normal map - // 5. bump map - // 6. roughnessMap map - // 7. metalnessMap map - // 8. alphaMap map - // 9. emissiveMap map - // 10. clearcoat map - // 11. clearcoat normal map - // 12. clearcoat roughnessMap map - // 13. specular intensity map - // 14. specular tint map - // 15. transmission map - // 16. thickness map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.displacementMap ) { - - uvScaleMap = material.displacementMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.roughnessMap ) { - - uvScaleMap = material.roughnessMap; - - } else if ( material.metalnessMap ) { - - uvScaleMap = material.metalnessMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } else if ( material.emissiveMap ) { - - uvScaleMap = material.emissiveMap; - - } else if ( material.clearcoatMap ) { - - uvScaleMap = material.clearcoatMap; - - } else if ( material.clearcoatNormalMap ) { - - uvScaleMap = material.clearcoatNormalMap; - - } else if ( material.clearcoatRoughnessMap ) { - - uvScaleMap = material.clearcoatRoughnessMap; - - } else if ( material.specularIntensityMap ) { - - uvScaleMap = material.specularIntensityMap; - - } else if ( material.specularTintMap ) { - - uvScaleMap = material.specularTintMap; - - } else if ( material.transmissionMap ) { - - uvScaleMap = material.transmissionMap; - - } else if ( material.thicknessMap ) { - - uvScaleMap = material.thicknessMap; - - } - - if ( uvScaleMap !== undefined ) { - - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - - // uv repeat and offset setting priorities for uv2 - // 1. ao map - // 2. light map - - let uv2ScaleMap; - - if ( material.aoMap ) { - - uv2ScaleMap = material.aoMap; - - } else if ( material.lightMap ) { - - uv2ScaleMap = material.lightMap; - - } - - if ( uv2ScaleMap !== undefined ) { - - // backwards compatibility - if ( uv2ScaleMap.isWebGLRenderTarget ) { - - uv2ScaleMap = uv2ScaleMap.texture; - - } - - if ( uv2ScaleMap.matrixAutoUpdate === true ) { - - uv2ScaleMap.updateMatrix(); - - } - - uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix ); - - } - - } - - function refreshUniformsLine( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - } - - function refreshUniformsDash( uniforms, material ) { - - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; - - } - - function refreshUniformsPoints( uniforms, material, pixelRatio, height ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size * pixelRatio; - uniforms.scale.value = height * 0.5; - - if ( material.map ) { - - uniforms.map.value = material.map; - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - - } - - function refreshUniformsSprites( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - uniforms.rotation.value = material.rotation; - - if ( material.map ) { - - uniforms.map.value = material.map; - - } - - if ( material.alphaMap ) { - - uniforms.alphaMap.value = material.alphaMap; - - } - - if ( material.alphaTest > 0 ) { - - uniforms.alphaTest.value = material.alphaTest; - - } - - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - - } - - function refreshUniformsLambert( uniforms, material ) { - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - } - - } - - function refreshUniformsPhong( uniforms, material ) { - - uniforms.specular.value.copy( material.specular ); - uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - } - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - } - - function refreshUniformsToon( uniforms, material ) { - - if ( material.gradientMap ) { - - uniforms.gradientMap.value = material.gradientMap; - - } - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - } - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - } - - function refreshUniformsStandard( uniforms, material ) { - - uniforms.roughness.value = material.roughness; - uniforms.metalness.value = material.metalness; - - if ( material.roughnessMap ) { - - uniforms.roughnessMap.value = material.roughnessMap; - - } - - if ( material.metalnessMap ) { - - uniforms.metalnessMap.value = material.metalnessMap; - - } - - if ( material.emissiveMap ) { - - uniforms.emissiveMap.value = material.emissiveMap; - - } - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - const envMap = properties.get( material ).envMap; - - if ( envMap ) { - - //uniforms.envMap.value = material.envMap; // part of uniforms common - uniforms.envMapIntensity.value = material.envMapIntensity; - - } - - } - - function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) { - - refreshUniformsStandard( uniforms, material ); - - uniforms.ior.value = material.ior; // also part of uniforms common - - if ( material.sheenTint ) uniforms.sheenTint.value.copy( material.sheenTint ); - - if ( material.clearcoat > 0 ) { - - uniforms.clearcoat.value = material.clearcoat; - uniforms.clearcoatRoughness.value = material.clearcoatRoughness; - - if ( material.clearcoatMap ) { - - uniforms.clearcoatMap.value = material.clearcoatMap; - - } - - if ( material.clearcoatRoughnessMap ) { - - uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; - - } - - if ( material.clearcoatNormalMap ) { - - uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); - uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; - - if ( material.side === BackSide ) { - - uniforms.clearcoatNormalScale.value.negate(); - - } - - } - - } - - if ( material.transmission > 0 ) { - - uniforms.transmission.value = material.transmission; - uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; - uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height ); - - if ( material.transmissionMap ) { - - uniforms.transmissionMap.value = material.transmissionMap; - - } - - uniforms.thickness.value = material.thickness; - - if ( material.thicknessMap ) { - - uniforms.thicknessMap.value = material.thicknessMap; - - } - - uniforms.attenuationDistance.value = material.attenuationDistance; - uniforms.attenuationTint.value.copy( material.attenuationTint ); - - } - - uniforms.specularIntensity.value = material.specularIntensity; - uniforms.specularTint.value.copy( material.specularTint ); - - if ( material.specularIntensityMap ) { - - uniforms.specularIntensityMap.value = material.specularIntensityMap; - - } - - if ( material.specularTintMap ) { - - uniforms.specularTintMap.value = material.specularTintMap; - - } - - } - - function refreshUniformsMatcap( uniforms, material ) { - - if ( material.matcap ) { - - uniforms.matcap.value = material.matcap; - - } - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - } - - function refreshUniformsDepth( uniforms, material ) { - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - } - - function refreshUniformsDistance( uniforms, material ) { - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - uniforms.referencePosition.value.copy( material.referencePosition ); - uniforms.nearDistance.value = material.nearDistance; - uniforms.farDistance.value = material.farDistance; - - } - - function refreshUniformsNormal( uniforms, material ) { - - if ( material.bumpMap ) { - - uniforms.bumpMap.value = material.bumpMap; - uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; - - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); - - } - - if ( material.displacementMap ) { - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - } - - } - - return { - refreshFogUniforms: refreshFogUniforms, - refreshMaterialUniforms: refreshMaterialUniforms - }; - - } - - function createCanvasElement() { - - const canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.style.display = 'block'; - return canvas; - - } - - function WebGLRenderer( parameters = {} ) { - - const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(), - _context = parameters.context !== undefined ? parameters.context : null, - - _alpha = parameters.alpha !== undefined ? parameters.alpha : false, - _depth = parameters.depth !== undefined ? parameters.depth : true, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, - _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default', - _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false; - - let currentRenderList = null; - let currentRenderState = null; - - // render() can be called from within a callback triggered by another render. - // We track this so that the nested render call gets its list and state isolated from the parent render call. - - const renderListStack = []; - const renderStateStack = []; - - // public properties - - this.domElement = _canvas; - - // Debug configuration container - this.debug = { - - /** - * Enables error checking and reporting when shader programs are being compiled - * @type {boolean} - */ - checkShaderErrors: true - }; - - // clearing - - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; - - // scene graph - - this.sortObjects = true; - - // user-defined clipping - - this.clippingPlanes = []; - this.localClippingEnabled = false; - - // physically based shading - - this.gammaFactor = 2.0; // for backwards compatibility - this.outputEncoding = LinearEncoding; - - // physical lights - - this.physicallyCorrectLights = false; - - // tone mapping - - this.toneMapping = NoToneMapping; - this.toneMappingExposure = 1.0; - - // internal properties - - const _this = this; - - let _isContextLost = false; - - // internal state cache - - let _currentActiveCubeFace = 0; - let _currentActiveMipmapLevel = 0; - let _currentRenderTarget = null; - let _currentMaterialId = - 1; - - let _currentCamera = null; - - const _currentViewport = new Vector4(); - const _currentScissor = new Vector4(); - let _currentScissorTest = null; - - // - - let _width = _canvas.width; - let _height = _canvas.height; - - let _pixelRatio = 1; - let _opaqueSort = null; - let _transparentSort = null; - - const _viewport = new Vector4( 0, 0, _width, _height ); - const _scissor = new Vector4( 0, 0, _width, _height ); - let _scissorTest = false; - - // - - const _currentDrawBuffers = []; - - // frustum - - const _frustum = new Frustum(); - - // clipping - - let _clippingEnabled = false; - let _localClippingEnabled = false; - - // transmission - - let _transmissionRenderTarget = null; - - // camera matrices cache - - const _projScreenMatrix = new Matrix4(); - - const _vector3 = new Vector3(); - - const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; - - function getTargetPixelRatio() { - - return _currentRenderTarget === null ? _pixelRatio : 1; - - } - - // initialize - - let _gl = _context; - - function getContext( contextNames, contextAttributes ) { - - for ( let i = 0; i < contextNames.length; i ++ ) { - - const contextName = contextNames[ i ]; - const context = _canvas.getContext( contextName, contextAttributes ); - if ( context !== null ) return context; - - } - - return null; - - } - - try { - - const contextAttributes = { - alpha: _alpha, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer, - powerPreference: _powerPreference, - failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat - }; - - // event listeners must be registered before WebGL context is created, see #12753 - - _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - - if ( _gl === null ) { - - const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; - - if ( _this.isWebGL1Renderer === true ) { - - contextNames.shift(); - - } - - _gl = getContext( contextNames, contextAttributes ); - - if ( _gl === null ) { - - if ( getContext( contextNames ) ) { - - throw new Error( 'Error creating WebGL context with your selected attributes.' ); - - } else { - - throw new Error( 'Error creating WebGL context.' ); - - } - - } - - } - - // Some experimental-webgl implementations do not have getShaderPrecisionFormat - - if ( _gl.getShaderPrecisionFormat === undefined ) { - - _gl.getShaderPrecisionFormat = function () { - - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; - - }; - - } - - } catch ( error ) { - - console.error( 'THREE.WebGLRenderer: ' + error.message ); - throw error; - - } - - let extensions, capabilities, state, info; - let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; - let programCache, materials, renderLists, renderStates, clipping, shadowMap; - - let background, morphtargets, bufferRenderer, indexedBufferRenderer; - - let utils, bindingStates; - - function initGLContext() { - - extensions = new WebGLExtensions( _gl ); - - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - - extensions.init( capabilities ); - - utils = new WebGLUtils( _gl, extensions, capabilities ); - - state = new WebGLState( _gl, extensions, capabilities ); - - _currentDrawBuffers[ 0 ] = 1029; - - info = new WebGLInfo(); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); - cubemaps = new WebGLCubeMaps( _this ); - cubeuvmaps = new WebGLCubeUVMaps( _this ); - attributes = new WebGLAttributes( _gl, capabilities ); - bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); - geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); - objects = new WebGLObjects( _gl, geometries, attributes, info ); - morphtargets = new WebGLMorphtargets( _gl ); - clipping = new WebGLClipping( properties ); - programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); - materials = new WebGLMaterials( properties ); - renderLists = new WebGLRenderLists( properties ); - renderStates = new WebGLRenderStates( extensions, capabilities ); - background = new WebGLBackground( _this, cubemaps, state, objects, _premultipliedAlpha ); - shadowMap = new WebGLShadowMap( _this, objects, capabilities ); - - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - - info.programs = programCache.programs; - - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.shadowMap = shadowMap; - _this.state = state; - _this.info = info; - - } - - initGLContext(); - - // xr - - const xr = new WebXRManager( _this, _gl ); - - this.xr = xr; - - // API - - this.getContext = function () { - - return _gl; - - }; - - this.getContextAttributes = function () { - - return _gl.getContextAttributes(); - - }; - - this.forceContextLoss = function () { - - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); - - }; - - this.forceContextRestore = function () { - - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); - - }; - - this.getPixelRatio = function () { - - return _pixelRatio; - - }; - - this.setPixelRatio = function ( value ) { - - if ( value === undefined ) return; - - _pixelRatio = value; - - this.setSize( _width, _height, false ); - - }; - - this.getSize = function ( target ) { - - return target.set( _width, _height ); - - }; - - this.setSize = function ( width, height, updateStyle ) { - - if ( xr.isPresenting ) { - - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; - - } - - _width = width; - _height = height; - - _canvas.width = Math.floor( width * _pixelRatio ); - _canvas.height = Math.floor( height * _pixelRatio ); - - if ( updateStyle !== false ) { - - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; - - } - - this.setViewport( 0, 0, width, height ); - - }; - - this.getDrawingBufferSize = function ( target ) { - - return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); - - }; - - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - - _width = width; - _height = height; - - _pixelRatio = pixelRatio; - - _canvas.width = Math.floor( width * pixelRatio ); - _canvas.height = Math.floor( height * pixelRatio ); - - this.setViewport( 0, 0, width, height ); - - }; - - this.getCurrentViewport = function ( target ) { - - return target.copy( _currentViewport ); - - }; - - this.getViewport = function ( target ) { - - return target.copy( _viewport ); - - }; - - this.setViewport = function ( x, y, width, height ) { - - if ( x.isVector4 ) { - - _viewport.set( x.x, x.y, x.z, x.w ); - - } else { - - _viewport.set( x, y, width, height ); - - } - - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - - }; - - this.getScissor = function ( target ) { - - return target.copy( _scissor ); - - }; - - this.setScissor = function ( x, y, width, height ) { - - if ( x.isVector4 ) { - - _scissor.set( x.x, x.y, x.z, x.w ); - - } else { - - _scissor.set( x, y, width, height ); - - } - - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); - - }; - - this.getScissorTest = function () { - - return _scissorTest; - - }; - - this.setScissorTest = function ( boolean ) { - - state.setScissorTest( _scissorTest = boolean ); - - }; - - this.setOpaqueSort = function ( method ) { - - _opaqueSort = method; - - }; - - this.setTransparentSort = function ( method ) { - - _transparentSort = method; - - }; - - // Clearing - - this.getClearColor = function ( target ) { - - return target.copy( background.getClearColor() ); - - }; - - this.setClearColor = function () { - - background.setClearColor.apply( background, arguments ); - - }; - - this.getClearAlpha = function () { - - return background.getClearAlpha(); - - }; - - this.setClearAlpha = function () { - - background.setClearAlpha.apply( background, arguments ); - - }; - - this.clear = function ( color, depth, stencil ) { - - let bits = 0; - - if ( color === undefined || color ) bits |= 16384; - if ( depth === undefined || depth ) bits |= 256; - if ( stencil === undefined || stencil ) bits |= 1024; - - _gl.clear( bits ); - - }; - - this.clearColor = function () { - - this.clear( true, false, false ); - - }; - - this.clearDepth = function () { - - this.clear( false, true, false ); - - }; - - this.clearStencil = function () { - - this.clear( false, false, true ); - - }; - - // - - this.dispose = function () { - - _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - cubemaps.dispose(); - cubeuvmaps.dispose(); - objects.dispose(); - bindingStates.dispose(); - - xr.dispose(); - - xr.removeEventListener( 'sessionstart', onXRSessionStart ); - xr.removeEventListener( 'sessionend', onXRSessionEnd ); - - if ( _transmissionRenderTarget ) { - - _transmissionRenderTarget.dispose(); - _transmissionRenderTarget = null; - - } - - animation.stop(); - - }; - - // Events - - function onContextLost( event ) { - - event.preventDefault(); - - console.log( 'THREE.WebGLRenderer: Context Lost.' ); - - _isContextLost = true; - - } - - function onContextRestore( /* event */ ) { - - console.log( 'THREE.WebGLRenderer: Context Restored.' ); - - _isContextLost = false; - - const infoAutoReset = info.autoReset; - const shadowMapEnabled = shadowMap.enabled; - const shadowMapAutoUpdate = shadowMap.autoUpdate; - const shadowMapNeedsUpdate = shadowMap.needsUpdate; - const shadowMapType = shadowMap.type; - - initGLContext(); - - info.autoReset = infoAutoReset; - shadowMap.enabled = shadowMapEnabled; - shadowMap.autoUpdate = shadowMapAutoUpdate; - shadowMap.needsUpdate = shadowMapNeedsUpdate; - shadowMap.type = shadowMapType; - - } - - function onMaterialDispose( event ) { - - const material = event.target; - - material.removeEventListener( 'dispose', onMaterialDispose ); - - deallocateMaterial( material ); - - } - - // Buffer deallocation - - function deallocateMaterial( material ) { - - releaseMaterialProgramReferences( material ); - - properties.remove( material ); - - } - - - function releaseMaterialProgramReferences( material ) { - - const programs = properties.get( material ).programs; - - if ( programs !== undefined ) { - - programs.forEach( function ( program ) { - - programCache.releaseProgram( program ); - - } ); - - } - - } - - // Buffer rendering - - function renderObjectImmediate( object, program ) { - - object.render( function ( object ) { - - _this.renderBufferImmediate( object, program ); - - } ); - - } - - this.renderBufferImmediate = function ( object, program ) { - - bindingStates.initAttributes(); - - const buffers = properties.get( object ); - - if ( object.hasPositions && ! buffers.position ) buffers.position = _gl.createBuffer(); - if ( object.hasNormals && ! buffers.normal ) buffers.normal = _gl.createBuffer(); - if ( object.hasUvs && ! buffers.uv ) buffers.uv = _gl.createBuffer(); - if ( object.hasColors && ! buffers.color ) buffers.color = _gl.createBuffer(); - - const programAttributes = program.getAttributes(); - - if ( object.hasPositions ) { - - _gl.bindBuffer( 34962, buffers.position ); - _gl.bufferData( 34962, object.positionArray, 35048 ); - - bindingStates.enableAttribute( programAttributes.position.location ); - _gl.vertexAttribPointer( programAttributes.position.location, 3, 5126, false, 0, 0 ); - - } - - if ( object.hasNormals ) { - - _gl.bindBuffer( 34962, buffers.normal ); - _gl.bufferData( 34962, object.normalArray, 35048 ); - - bindingStates.enableAttribute( programAttributes.normal.location ); - _gl.vertexAttribPointer( programAttributes.normal.location, 3, 5126, false, 0, 0 ); - - } - - if ( object.hasUvs ) { - - _gl.bindBuffer( 34962, buffers.uv ); - _gl.bufferData( 34962, object.uvArray, 35048 ); - - bindingStates.enableAttribute( programAttributes.uv.location ); - _gl.vertexAttribPointer( programAttributes.uv.location, 2, 5126, false, 0, 0 ); - - } - - if ( object.hasColors ) { - - _gl.bindBuffer( 34962, buffers.color ); - _gl.bufferData( 34962, object.colorArray, 35048 ); - - bindingStates.enableAttribute( programAttributes.color.location ); - _gl.vertexAttribPointer( programAttributes.color.location, 3, 5126, false, 0, 0 ); - - } - - bindingStates.disableUnusedAttributes(); - - _gl.drawArrays( 4, 0, object.count ); - - object.count = 0; - - }; - - this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { - - if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) - - const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); - - const program = setProgram( camera, scene, material, object ); - - state.setMaterial( material, frontFaceCW ); - - // - - let index = geometry.index; - const position = geometry.attributes.position; - - // - - if ( index === null ) { - - if ( position === undefined || position.count === 0 ) return; - - } else if ( index.count === 0 ) { - - return; - - } - - // - - let rangeFactor = 1; - - if ( material.wireframe === true ) { - - index = geometries.getWireframeAttribute( geometry ); - rangeFactor = 2; - - } - - if ( geometry.morphAttributes.position !== undefined || geometry.morphAttributes.normal !== undefined ) { - - morphtargets.update( object, geometry, material, program ); - - } - - bindingStates.setup( object, material, program, geometry, index ); - - let attribute; - let renderer = bufferRenderer; - - if ( index !== null ) { - - attribute = attributes.get( index ); - - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); - - } - - // - - const dataCount = ( index !== null ) ? index.count : position.count; - - const rangeStart = geometry.drawRange.start * rangeFactor; - const rangeCount = geometry.drawRange.count * rangeFactor; - - const groupStart = group !== null ? group.start * rangeFactor : 0; - const groupCount = group !== null ? group.count * rangeFactor : Infinity; - - const drawStart = Math.max( rangeStart, groupStart ); - const drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; - - const drawCount = Math.max( 0, drawEnd - drawStart + 1 ); - - if ( drawCount === 0 ) return; - - // - - if ( object.isMesh ) { - - if ( material.wireframe === true ) { - - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( 1 ); - - } else { - - renderer.setMode( 4 ); - - } - - } else if ( object.isLine ) { - - let lineWidth = material.linewidth; - - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - - state.setLineWidth( lineWidth * getTargetPixelRatio() ); - - if ( object.isLineSegments ) { - - renderer.setMode( 1 ); - - } else if ( object.isLineLoop ) { - - renderer.setMode( 2 ); - - } else { - - renderer.setMode( 3 ); - - } - - } else if ( object.isPoints ) { - - renderer.setMode( 0 ); - - } else if ( object.isSprite ) { - - renderer.setMode( 4 ); - - } - - if ( object.isInstancedMesh ) { - - renderer.renderInstances( drawStart, drawCount, object.count ); - - } else if ( geometry.isInstancedBufferGeometry ) { - - const instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount ); - - renderer.renderInstances( drawStart, drawCount, instanceCount ); - - } else { - - renderer.render( drawStart, drawCount ); - - } - - }; - - // Compile - - this.compile = function ( scene, camera ) { - - currentRenderState = renderStates.get( scene ); - currentRenderState.init(); - - renderStateStack.push( currentRenderState ); - - scene.traverseVisible( function ( object ) { - - if ( object.isLight && object.layers.test( camera.layers ) ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } - - } ); - - currentRenderState.setupLights( _this.physicallyCorrectLights ); - - scene.traverse( function ( object ) { - - const material = object.material; - - if ( material ) { - - if ( Array.isArray( material ) ) { - - for ( let i = 0; i < material.length; i ++ ) { - - const material2 = material[ i ]; - - getProgram( material2, scene, object ); - - } - - } else { - - getProgram( material, scene, object ); - - } - - } - - } ); - - renderStateStack.pop(); - currentRenderState = null; - - }; - - // Animation Loop - - let onAnimationFrameCallback = null; - - function onAnimationFrame( time ) { - - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); - - } - - function onXRSessionStart() { - - animation.stop(); - - } - - function onXRSessionEnd() { - - animation.start(); - - } - - const animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); - - if ( typeof window !== 'undefined' ) animation.setContext( window ); - - this.setAnimationLoop = function ( callback ) { - - onAnimationFrameCallback = callback; - xr.setAnimationLoop( callback ); - - ( callback === null ) ? animation.stop() : animation.start(); - - }; - - xr.addEventListener( 'sessionstart', onXRSessionStart ); - xr.addEventListener( 'sessionend', onXRSessionEnd ); - - // Rendering - - this.render = function ( scene, camera ) { - - if ( camera !== undefined && camera.isCamera !== true ) { - - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; - - } - - if ( _isContextLost === true ) return; - - // update scene graph - - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); - - // update camera matrices and frustum - - if ( camera.parent === null ) camera.updateMatrixWorld(); - - if ( xr.enabled === true && xr.isPresenting === true ) { - - if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); - - camera = xr.getCamera(); // use XR camera for rendering - - } - - // - if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); - - currentRenderState = renderStates.get( scene, renderStateStack.length ); - currentRenderState.init(); - - renderStateStack.push( currentRenderState ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromProjectionMatrix( _projScreenMatrix ); - - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); - - currentRenderList = renderLists.get( scene, renderListStack.length ); - currentRenderList.init(); - - renderListStack.push( currentRenderList ); - - projectObject( scene, camera, 0, _this.sortObjects ); - - currentRenderList.finish(); - - if ( _this.sortObjects === true ) { - - currentRenderList.sort( _opaqueSort, _transparentSort ); - - } - - // - - if ( _clippingEnabled === true ) clipping.beginShadows(); - - const shadowsArray = currentRenderState.state.shadowsArray; - - shadowMap.render( shadowsArray, scene, camera ); - - if ( _clippingEnabled === true ) clipping.endShadows(); - - // - - if ( this.info.autoReset === true ) this.info.reset(); - - // - - background.render( currentRenderList, scene ); - - // render scene - - currentRenderState.setupLights( _this.physicallyCorrectLights ); - - if ( camera.isArrayCamera ) { - - const cameras = camera.cameras; - - for ( let i = 0, l = cameras.length; i < l; i ++ ) { - - const camera2 = cameras[ i ]; - - renderScene( currentRenderList, scene, camera2, camera2.viewport ); - - } - - } else { - - renderScene( currentRenderList, scene, camera ); - - } - - // - - if ( _currentRenderTarget !== null ) { - - // resolve multisample renderbuffers to a single-sample texture if necessary - - textures.updateMultisampleRenderTarget( _currentRenderTarget ); - - // Generate mipmap if we're using any kind of mipmap filtering - - textures.updateRenderTargetMipmap( _currentRenderTarget ); - - } - - // - - if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); - - // Ensure depth buffer writing is enabled so it can be cleared on next render - - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); - - state.setPolygonOffset( false ); - - // _gl.finish(); - - bindingStates.resetDefaultState(); - _currentMaterialId = - 1; - _currentCamera = null; - - renderStateStack.pop(); - - if ( renderStateStack.length > 0 ) { - - currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; - - } else { - - currentRenderState = null; - - } - - renderListStack.pop(); - - if ( renderListStack.length > 0 ) { - - currentRenderList = renderListStack[ renderListStack.length - 1 ]; - - } else { - - currentRenderList = null; - - } - - }; - - function projectObject( object, camera, groupOrder, sortObjects ) { - - if ( object.visible === false ) return; - - const visible = object.layers.test( camera.layers ); - - if ( visible ) { - - if ( object.isGroup ) { - - groupOrder = object.renderOrder; - - } else if ( object.isLOD ) { - - if ( object.autoUpdate === true ) object.update( camera ); - - } else if ( object.isLight ) { - - currentRenderState.pushLight( object ); - - if ( object.castShadow ) { - - currentRenderState.pushShadow( object ); - - } - - } else if ( object.isSprite ) { - - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - - if ( sortObjects ) { - - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - const geometry = objects.update( object ); - const material = object.material; - - if ( material.visible ) { - - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - - } - - } - - } else if ( object.isImmediateRenderObject ) { - - if ( sortObjects ) { - - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - currentRenderList.push( object, null, object.material, groupOrder, _vector3.z, null ); - - } else if ( object.isMesh || object.isLine || object.isPoints ) { - - if ( object.isSkinnedMesh ) { - - // update skeleton only once in a frame - - if ( object.skeleton.frame !== info.render.frame ) { - - object.skeleton.update(); - object.skeleton.frame = info.render.frame; - - } - - } - - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - - if ( sortObjects ) { - - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); - - } - - const geometry = objects.update( object ); - const material = object.material; - - if ( Array.isArray( material ) ) { - - const groups = geometry.groups; - - for ( let i = 0, l = groups.length; i < l; i ++ ) { - - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; - - if ( groupMaterial && groupMaterial.visible ) { - - currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); - - } - - } - - } else if ( material.visible ) { - - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - - } - - } - - } - - } - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - projectObject( children[ i ], camera, groupOrder, sortObjects ); - - } - - } - - function renderScene( currentRenderList, scene, camera, viewport ) { - - const opaqueObjects = currentRenderList.opaque; - const transmissiveObjects = currentRenderList.transmissive; - const transparentObjects = currentRenderList.transparent; - - currentRenderState.setupLightsView( camera ); - - if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, scene, camera ); - - if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); - - if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); - if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); - if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); - - } - - function renderTransmissionPass( opaqueObjects, scene, camera ) { - - if ( _transmissionRenderTarget === null ) { - - const needsAntialias = _antialias === true && capabilities.isWebGL2 === true; - const renderTargetType = needsAntialias ? WebGLMultisampleRenderTarget : WebGLRenderTarget; - - _transmissionRenderTarget = new renderTargetType( 1024, 1024, { - generateMipmaps: true, - type: utils.convert( HalfFloatType ) !== null ? HalfFloatType : UnsignedByteType, - minFilter: LinearMipmapLinearFilter, - magFilter: NearestFilter, - wrapS: ClampToEdgeWrapping, - wrapT: ClampToEdgeWrapping - } ); - - } - - const currentRenderTarget = _this.getRenderTarget(); - _this.setRenderTarget( _transmissionRenderTarget ); - _this.clear(); - - // Turn off the features which can affect the frag color for opaque objects pass. - // Otherwise they are applied twice in opaque objects pass and transmission objects pass. - const currentToneMapping = _this.toneMapping; - _this.toneMapping = NoToneMapping; - - renderObjects( opaqueObjects, scene, camera ); - - _this.toneMapping = currentToneMapping; - - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - - _this.setRenderTarget( currentRenderTarget ); - - } - - function renderObjects( renderList, scene, camera ) { - - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - - for ( let i = 0, l = renderList.length; i < l; i ++ ) { - - const renderItem = renderList[ i ]; - - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = overrideMaterial === null ? renderItem.material : overrideMaterial; - const group = renderItem.group; - - if ( object.layers.test( camera.layers ) ) { - - renderObject( object, scene, camera, geometry, material, group ); - - } - - } - - } - - function renderObject( object, scene, camera, geometry, material, group ) { - - object.onBeforeRender( _this, scene, camera, geometry, material, group ); - - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - - if ( object.isImmediateRenderObject ) { - - const program = setProgram( camera, scene, material, object ); - - state.setMaterial( material ); - - bindingStates.reset(); - - renderObjectImmediate( object, program ); - - } else { - - if ( material.transparent === true && material.side === DoubleSide ) { - - material.side = BackSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - material.side = FrontSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - material.side = DoubleSide; - - } else { - - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - - } - - } - - object.onAfterRender( _this, scene, camera, geometry, material, group ); - - } - - function getProgram( material, scene, object ) { - - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - - const materialProperties = properties.get( material ); - - const lights = currentRenderState.state.lights; - const shadowsArray = currentRenderState.state.shadowsArray; - - const lightsStateVersion = lights.state.version; - - const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); - const programCacheKey = programCache.getProgramCacheKey( parameters ); - - let programs = materialProperties.programs; - - // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change - - materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; - materialProperties.fog = scene.fog; - materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); - - if ( programs === undefined ) { - - // new material - - material.addEventListener( 'dispose', onMaterialDispose ); - - programs = new Map(); - materialProperties.programs = programs; - - } - - let program = programs.get( programCacheKey ); - - if ( program !== undefined ) { - - // early out if program and light state is identical - - if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { - - updateCommonMaterialProperties( material, parameters ); - - return program; - - } - - } else { - - parameters.uniforms = programCache.getUniforms( material ); - - material.onBuild( parameters, _this ); - - material.onBeforeCompile( parameters, _this ); - - program = programCache.acquireProgram( parameters, programCacheKey ); - programs.set( programCacheKey, program ); - - materialProperties.uniforms = parameters.uniforms; - - } - - const uniforms = materialProperties.uniforms; - - if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { - - uniforms.clippingPlanes = clipping.uniform; - - } - - updateCommonMaterialProperties( material, parameters ); - - // store the light setup it was created for - - materialProperties.needsLights = materialNeedsLights( material ); - materialProperties.lightsStateVersion = lightsStateVersion; - - if ( materialProperties.needsLights ) { - - // wire up the material to this renderer's lighting state - - uniforms.ambientLightColor.value = lights.state.ambient; - uniforms.lightProbe.value = lights.state.probe; - uniforms.directionalLights.value = lights.state.directional; - uniforms.directionalLightShadows.value = lights.state.directionalShadow; - uniforms.spotLights.value = lights.state.spot; - uniforms.spotLightShadows.value = lights.state.spotShadow; - uniforms.rectAreaLights.value = lights.state.rectArea; - uniforms.ltc_1.value = lights.state.rectAreaLTC1; - uniforms.ltc_2.value = lights.state.rectAreaLTC2; - uniforms.pointLights.value = lights.state.point; - uniforms.pointLightShadows.value = lights.state.pointShadow; - uniforms.hemisphereLights.value = lights.state.hemi; - - uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; - uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; - uniforms.spotShadowMap.value = lights.state.spotShadowMap; - uniforms.spotShadowMatrix.value = lights.state.spotShadowMatrix; - uniforms.pointShadowMap.value = lights.state.pointShadowMap; - uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; - // TODO (abelnation): add area lights shadow info to uniforms - - } - - const progUniforms = program.getUniforms(); - const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); - - materialProperties.currentProgram = program; - materialProperties.uniformsList = uniformsList; - - return program; - - } - - function updateCommonMaterialProperties( material, parameters ) { - - const materialProperties = properties.get( material ); - - materialProperties.outputEncoding = parameters.outputEncoding; - materialProperties.instancing = parameters.instancing; - materialProperties.skinning = parameters.skinning; - materialProperties.morphTargets = parameters.morphTargets; - materialProperties.morphNormals = parameters.morphNormals; - materialProperties.numClippingPlanes = parameters.numClippingPlanes; - materialProperties.numIntersection = parameters.numClipIntersection; - materialProperties.vertexAlphas = parameters.vertexAlphas; - materialProperties.vertexTangents = parameters.vertexTangents; - - } - - function setProgram( camera, scene, material, object ) { - - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - - textures.resetTextureUnits(); - - const fog = scene.fog; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : _currentRenderTarget.texture.encoding; - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const vertexAlphas = material.vertexColors === true && !! object.geometry && !! object.geometry.attributes.color && object.geometry.attributes.color.itemSize === 4; - const vertexTangents = !! object.geometry && !! object.geometry.attributes.tangent; - const morphTargets = !! object.geometry && !! object.geometry.morphAttributes.position; - const morphNormals = !! object.geometry && !! object.geometry.morphAttributes.normal; - - const materialProperties = properties.get( material ); - const lights = currentRenderState.state.lights; - - if ( _clippingEnabled === true ) { - - if ( _localClippingEnabled === true || camera !== _currentCamera ) { - - const useCache = - camera === _currentCamera && - material.id === _currentMaterialId; - - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - clipping.setState( material, camera, useCache ); - - } - - } - - // - - let needsProgramChange = false; - - if ( material.version === materialProperties.__version ) { - - if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { - - needsProgramChange = true; - - } else if ( materialProperties.outputEncoding !== encoding ) { - - needsProgramChange = true; - - } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { - - needsProgramChange = true; - - } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { - - needsProgramChange = true; - - } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { - - needsProgramChange = true; - - } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { - - needsProgramChange = true; - - } else if ( materialProperties.envMap !== envMap ) { - - needsProgramChange = true; - - } else if ( material.fog && materialProperties.fog !== fog ) { - - needsProgramChange = true; - - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== clipping.numPlanes || - materialProperties.numIntersection !== clipping.numIntersection ) ) { - - needsProgramChange = true; - - } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { - - needsProgramChange = true; - - } else if ( materialProperties.vertexTangents !== vertexTangents ) { - - needsProgramChange = true; - - } else if ( materialProperties.morphTargets !== morphTargets ) { - - needsProgramChange = true; - - } else if ( materialProperties.morphNormals !== morphNormals ) { - - needsProgramChange = true; - - } - - } else { - - needsProgramChange = true; - materialProperties.__version = material.version; - - } - - // - - let program = materialProperties.currentProgram; - - if ( needsProgramChange === true ) { - - program = getProgram( material, scene, object ); - - } - - let refreshProgram = false; - let refreshMaterial = false; - let refreshLights = false; - - const p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.uniforms; - - if ( state.useProgram( program.program ) ) { - - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; - - } - - if ( material.id !== _currentMaterialId ) { - - _currentMaterialId = material.id; - - refreshMaterial = true; - - } - - if ( refreshProgram || _currentCamera !== camera ) { - - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); - - if ( capabilities.logarithmicDepthBuffer ) { - - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - - } - - if ( _currentCamera !== camera ) { - - _currentCamera = camera; - - // lighting uniforms depend on the camera so enforce an update - // now, in case this material supports lights - or later, when - // the next material that does gets activated: - - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done - - } - - // load material specific uniforms - // (shader material also gets them for the sake of genericity) - - if ( material.isShaderMaterial || - material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshStandardMaterial || - material.envMap ) { - - const uCamPos = p_uniforms.map.cameraPosition; - - if ( uCamPos !== undefined ) { - - uCamPos.setValue( _gl, - _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - - } - - } - - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial ) { - - p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); - - } - - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial || - material.isShadowMaterial || - object.isSkinnedMesh ) { - - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - - } - - } - - // skinning uniforms must be set even if material didn't change - // auto-setting of texture unit for bone texture must go before other textures - // otherwise textures used for skinning can take over texture units reserved for other material textures - - if ( object.isSkinnedMesh ) { - - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - - const skeleton = object.skeleton; - - if ( skeleton ) { - - if ( capabilities.floatVertexTextures ) { - - if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); - - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); - - } else { - - p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); - - } - - } - - } - - if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { - - materialProperties.receiveShadow = object.receiveShadow; - p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); - - } - - if ( refreshMaterial ) { - - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - - if ( materialProperties.needsLights ) { - - // the current material requires lighting info - - // note: all lighting uniforms are always set correctly - // they simply reference the renderer's state for their - // values - // - // use the current material's .needsUpdate flags to set - // the GL state when required - - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - - } - - // refresh uniforms common to several materials - - if ( fog && material.fog ) { - - materials.refreshFogUniforms( m_uniforms, fog ); - - } - - materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); - - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); - - } - - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); - material.uniformsNeedUpdate = false; - - } - - if ( material.isSpriteMaterial ) { - - p_uniforms.setValue( _gl, 'center', object.center ); - - } - - // common matrices - - p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); - p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); - p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - - return program; - - } - - // If uniforms are marked as clean, they don't need to be loaded to the GPU. - - function markUniformsLightsNeedsUpdate( uniforms, value ) { - - uniforms.ambientLightColor.needsUpdate = value; - uniforms.lightProbe.needsUpdate = value; - - uniforms.directionalLights.needsUpdate = value; - uniforms.directionalLightShadows.needsUpdate = value; - uniforms.pointLights.needsUpdate = value; - uniforms.pointLightShadows.needsUpdate = value; - uniforms.spotLights.needsUpdate = value; - uniforms.spotLightShadows.needsUpdate = value; - uniforms.rectAreaLights.needsUpdate = value; - uniforms.hemisphereLights.needsUpdate = value; - - } - - function materialNeedsLights( material ) { - - return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || - material.isMeshStandardMaterial || material.isShadowMaterial || - ( material.isShaderMaterial && material.lights === true ); - - } - - this.getActiveCubeFace = function () { - - return _currentActiveCubeFace; - - }; - - this.getActiveMipmapLevel = function () { - - return _currentActiveMipmapLevel; - - }; - - this.getRenderTarget = function () { - - return _currentRenderTarget; - - }; - - this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { - - _currentRenderTarget = renderTarget; - _currentActiveCubeFace = activeCubeFace; - _currentActiveMipmapLevel = activeMipmapLevel; - - if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { - - textures.setupRenderTarget( renderTarget ); - - } - - let framebuffer = null; - let isCube = false; - let isRenderTarget3D = false; - - if ( renderTarget ) { - - const texture = renderTarget.texture; - - if ( texture.isDataTexture3D || texture.isDataTexture2DArray ) { - - isRenderTarget3D = true; - - } - - const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - - if ( renderTarget.isWebGLCubeRenderTarget ) { - - framebuffer = __webglFramebuffer[ activeCubeFace ]; - isCube = true; - - } else if ( renderTarget.isWebGLMultisampleRenderTarget ) { - - framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; - - } else { - - framebuffer = __webglFramebuffer; - - } - - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; - - } else { - - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); - _currentScissorTest = _scissorTest; - - } - - const framebufferBound = state.bindFramebuffer( 36160, framebuffer ); - - if ( framebufferBound && capabilities.drawBuffers ) { - - let needsUpdate = false; - - if ( renderTarget ) { - - if ( renderTarget.isWebGLMultipleRenderTargets ) { - - const textures = renderTarget.texture; - - if ( _currentDrawBuffers.length !== textures.length || _currentDrawBuffers[ 0 ] !== 36064 ) { - - for ( let i = 0, il = textures.length; i < il; i ++ ) { - - _currentDrawBuffers[ i ] = 36064 + i; - - } - - _currentDrawBuffers.length = textures.length; - - needsUpdate = true; - - } - - } else { - - if ( _currentDrawBuffers.length !== 1 || _currentDrawBuffers[ 0 ] !== 36064 ) { - - _currentDrawBuffers[ 0 ] = 36064; - _currentDrawBuffers.length = 1; - - needsUpdate = true; - - } - - } - - } else { - - if ( _currentDrawBuffers.length !== 1 || _currentDrawBuffers[ 0 ] !== 1029 ) { - - _currentDrawBuffers[ 0 ] = 1029; - _currentDrawBuffers.length = 1; - - needsUpdate = true; - - } - - } - - if ( needsUpdate ) { - - if ( capabilities.isWebGL2 ) { - - _gl.drawBuffers( _currentDrawBuffers ); - - } else { - - extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( _currentDrawBuffers ); - - } - - } - - } - - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); - - if ( isCube ) { - - const textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); - - } else if ( isRenderTarget3D ) { - - const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( 36160, 36064, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); - - } - - _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings - - }; - - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { - - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; - - } - - let framebuffer = properties.get( renderTarget ).__webglFramebuffer; - - if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { - - framebuffer = framebuffer[ activeCubeFaceIndex ]; - - } - - if ( framebuffer ) { - - state.bindFramebuffer( 36160, framebuffer ); - - try { - - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; - - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; - - } - - const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); - - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! halfFloatSupportedByExt ) { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; - - } - - if ( _gl.checkFramebufferStatus( 36160 ) === 36053 ) { - - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); - - } - - } else { - - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - - } - - } finally { - - // restore framebuffer of current render target if necessary - - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( 36160, framebuffer ); - - } - - } - - }; - - this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { - - const levelScale = Math.pow( 2, - level ); - const width = Math.floor( texture.image.width * levelScale ); - const height = Math.floor( texture.image.height * levelScale ); - - let glFormat = utils.convert( texture.format ); - - if ( capabilities.isWebGL2 ) { - - // Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1120100 - // Not needed in Chrome 93+ - - if ( glFormat === 6407 ) glFormat = 32849; - if ( glFormat === 6408 ) glFormat = 32856; - - } - - textures.setTexture2D( texture, 0 ); - - _gl.copyTexImage2D( 3553, level, glFormat, position.x, position.y, width, height, 0 ); - - state.unbindTexture(); - - }; - - this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { - - const width = srcTexture.image.width; - const height = srcTexture.image.height; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - - textures.setTexture2D( dstTexture, 0 ); - - // As another texture upload may have changed pixelStorei - // parameters, make sure they are correct for the dstTexture - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); - - if ( srcTexture.isDataTexture ) { - - _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - - } else { - - if ( srcTexture.isCompressedTexture ) { - - _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); - - } else { - - _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image ); - - } - - } - - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 ); - - state.unbindTexture(); - - }; - - this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { - - if ( _this.isWebGL1Renderer ) { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); - return; - - } - - const width = sourceBox.max.x - sourceBox.min.x + 1; - const height = sourceBox.max.y - sourceBox.min.y + 1; - const depth = sourceBox.max.z - sourceBox.min.z + 1; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - let glTarget; - - if ( dstTexture.isDataTexture3D ) { - - textures.setTexture3D( dstTexture, 0 ); - glTarget = 32879; - - } else if ( dstTexture.isDataTexture2DArray ) { - - textures.setTexture2DArray( dstTexture, 0 ); - glTarget = 35866; - - } else { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); - return; - - } - - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); - - const unpackRowLen = _gl.getParameter( 3314 ); - const unpackImageHeight = _gl.getParameter( 32878 ); - const unpackSkipPixels = _gl.getParameter( 3316 ); - const unpackSkipRows = _gl.getParameter( 3315 ); - const unpackSkipImages = _gl.getParameter( 32877 ); - - const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ 0 ] : srcTexture.image; - - _gl.pixelStorei( 3314, image.width ); - _gl.pixelStorei( 32878, image.height ); - _gl.pixelStorei( 3316, sourceBox.min.x ); - _gl.pixelStorei( 3315, sourceBox.min.y ); - _gl.pixelStorei( 32877, sourceBox.min.z ); - - if ( srcTexture.isDataTexture || srcTexture.isDataTexture3D ) { - - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); - - } else { - - if ( srcTexture.isCompressedTexture ) { - - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); - _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); - - } else { - - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); - - } - - } - - _gl.pixelStorei( 3314, unpackRowLen ); - _gl.pixelStorei( 32878, unpackImageHeight ); - _gl.pixelStorei( 3316, unpackSkipPixels ); - _gl.pixelStorei( 3315, unpackSkipRows ); - _gl.pixelStorei( 32877, unpackSkipImages ); - - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); - - state.unbindTexture(); - - }; - - this.initTexture = function ( texture ) { - - textures.setTexture2D( texture, 0 ); - - state.unbindTexture(); - - }; - - this.resetState = function () { - - _currentActiveCubeFace = 0; - _currentActiveMipmapLevel = 0; - _currentRenderTarget = null; - - state.reset(); - bindingStates.reset(); - - }; - - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef - - } - - } - - class WebGL1Renderer extends WebGLRenderer {} - - WebGL1Renderer.prototype.isWebGL1Renderer = true; - - class FogExp2 { - - constructor( color, density = 0.00025 ) { - - this.name = ''; - - this.color = new Color( color ); - this.density = density; - - } - - clone() { - - return new FogExp2( this.color, this.density ); - - } - - toJSON( /* meta */ ) { - - return { - type: 'FogExp2', - color: this.color.getHex(), - density: this.density - }; - - } - - } - - FogExp2.prototype.isFogExp2 = true; - - class Fog { - - constructor( color, near = 1, far = 1000 ) { - - this.name = ''; - - this.color = new Color( color ); - - this.near = near; - this.far = far; - - } - - clone() { - - return new Fog( this.color, this.near, this.far ); - - } - - toJSON( /* meta */ ) { - - return { - type: 'Fog', - color: this.color.getHex(), - near: this.near, - far: this.far - }; - - } - - } - - Fog.prototype.isFog = true; - - class Scene extends Object3D { - - constructor() { - - super(); - - this.type = 'Scene'; - - this.background = null; - this.environment = null; - this.fog = null; - - this.overrideMaterial = null; - - this.autoUpdate = true; // checked by the renderer - - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef - - } - - } - - copy( source, recursive ) { - - super.copy( source, recursive ); - - if ( source.background !== null ) this.background = source.background.clone(); - if ( source.environment !== null ) this.environment = source.environment.clone(); - if ( source.fog !== null ) this.fog = source.fog.clone(); - - if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); - - this.autoUpdate = source.autoUpdate; - this.matrixAutoUpdate = source.matrixAutoUpdate; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - - return data; - - } - - } - - Scene.prototype.isScene = true; - - class InterleavedBuffer { - - constructor( array, stride ) { - - this.array = array; - this.stride = stride; - this.count = array !== undefined ? array.length / stride : 0; - - this.usage = StaticDrawUsage; - this.updateRange = { offset: 0, count: - 1 }; - - this.version = 0; - - this.uuid = generateUUID(); - - } - - onUploadCallback() {} - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - setUsage( value ) { - - this.usage = value; - - return this; - - } - - copy( source ) { - - this.array = new source.array.constructor( source.array ); - this.count = source.count; - this.stride = source.stride; - this.usage = source.usage; - - return this; - - } - - copyAt( index1, attribute, index2 ) { - - index1 *= this.stride; - index2 *= attribute.stride; - - for ( let i = 0, l = this.stride; i < l; i ++ ) { - - this.array[ index1 + i ] = attribute.array[ index2 + i ]; - - } - - return this; - - } - - set( value, offset = 0 ) { - - this.array.set( value, offset ); - - return this; - - } - - clone( data ) { - - if ( data.arrayBuffers === undefined ) { - - data.arrayBuffers = {}; - - } - - if ( this.array.buffer._uuid === undefined ) { - - this.array.buffer._uuid = generateUUID(); - - } - - if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - - data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; - - } - - const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); - - const ib = new this.constructor( array, this.stride ); - ib.setUsage( this.usage ); - - return ib; - - } - - onUpload( callback ) { - - this.onUploadCallback = callback; - - return this; - - } - - toJSON( data ) { - - if ( data.arrayBuffers === undefined ) { - - data.arrayBuffers = {}; - - } - - // generate UUID for array buffer if necessary - - if ( this.array.buffer._uuid === undefined ) { - - this.array.buffer._uuid = generateUUID(); - - } - - if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - - data.arrayBuffers[ this.array.buffer._uuid ] = Array.prototype.slice.call( new Uint32Array( this.array.buffer ) ); - - } - - // - - return { - uuid: this.uuid, - buffer: this.array.buffer._uuid, - type: this.array.constructor.name, - stride: this.stride - }; - - } - - } - - InterleavedBuffer.prototype.isInterleavedBuffer = true; - - const _vector$6 = /*@__PURE__*/ new Vector3(); - - class InterleavedBufferAttribute { - - constructor( interleavedBuffer, itemSize, offset, normalized = false ) { - - this.name = ''; - - this.data = interleavedBuffer; - this.itemSize = itemSize; - this.offset = offset; - - this.normalized = normalized === true; - - } - - get count() { - - return this.data.count; - - } - - get array() { - - return this.data.array; - - } - - set needsUpdate( value ) { - - this.data.needsUpdate = value; - - } - - applyMatrix4( m ) { - - for ( let i = 0, l = this.data.count; i < l; i ++ ) { - - _vector$6.x = this.getX( i ); - _vector$6.y = this.getY( i ); - _vector$6.z = this.getZ( i ); - - _vector$6.applyMatrix4( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - applyNormalMatrix( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$6.x = this.getX( i ); - _vector$6.y = this.getY( i ); - _vector$6.z = this.getZ( i ); - - _vector$6.applyNormalMatrix( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - transformDirection( m ) { - - for ( let i = 0, l = this.count; i < l; i ++ ) { - - _vector$6.x = this.getX( i ); - _vector$6.y = this.getY( i ); - _vector$6.z = this.getZ( i ); - - _vector$6.transformDirection( m ); - - this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - - } - - return this; - - } - - setX( index, x ) { - - this.data.array[ index * this.data.stride + this.offset ] = x; - - return this; - - } - - setY( index, y ) { - - this.data.array[ index * this.data.stride + this.offset + 1 ] = y; - - return this; - - } - - setZ( index, z ) { - - this.data.array[ index * this.data.stride + this.offset + 2 ] = z; - - return this; - - } - - setW( index, w ) { - - this.data.array[ index * this.data.stride + this.offset + 3 ] = w; - - return this; - - } - - getX( index ) { - - return this.data.array[ index * this.data.stride + this.offset ]; - - } - - getY( index ) { - - return this.data.array[ index * this.data.stride + this.offset + 1 ]; - - } - - getZ( index ) { - - return this.data.array[ index * this.data.stride + this.offset + 2 ]; - - } - - getW( index ) { - - return this.data.array[ index * this.data.stride + this.offset + 3 ]; - - } - - setXY( index, x, y ) { - - index = index * this.data.stride + this.offset; - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - - return this; - - } - - setXYZ( index, x, y, z ) { - - index = index * this.data.stride + this.offset; - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - - return this; - - } - - setXYZW( index, x, y, z, w ) { - - index = index * this.data.stride + this.offset; - - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; - this.data.array[ index + 3 ] = w; - - return this; - - } - - clone( data ) { - - if ( data === undefined ) { - - console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interlaved buffer attribute will deinterleave buffer data.' ); - - const array = []; - - for ( let i = 0; i < this.count; i ++ ) { - - const index = i * this.data.stride + this.offset; - - for ( let j = 0; j < this.itemSize; j ++ ) { - - array.push( this.data.array[ index + j ] ); - - } - - } - - return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); - - } else { - - if ( data.interleavedBuffers === undefined ) { - - data.interleavedBuffers = {}; - - } - - if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - - data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); - - } - - return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); - - } - - } - - toJSON( data ) { - - if ( data === undefined ) { - - console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interlaved buffer attribute will deinterleave buffer data.' ); - - const array = []; - - for ( let i = 0; i < this.count; i ++ ) { - - const index = i * this.data.stride + this.offset; - - for ( let j = 0; j < this.itemSize; j ++ ) { - - array.push( this.data.array[ index + j ] ); - - } - - } - - // deinterleave data and save it as an ordinary buffer attribute for now - - return { - itemSize: this.itemSize, - type: this.array.constructor.name, - array: array, - normalized: this.normalized - }; - - } else { - - // save as true interlaved attribtue - - if ( data.interleavedBuffers === undefined ) { - - data.interleavedBuffers = {}; - - } - - if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - - data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); - - } - - return { - isInterleavedBufferAttribute: true, - itemSize: this.itemSize, - data: this.data.uuid, - offset: this.offset, - normalized: this.normalized - }; - - } - - } - - } - - InterleavedBufferAttribute.prototype.isInterleavedBufferAttribute = true; - - /** - * parameters = { - * color: , - * map: new THREE.Texture( ), - * alphaMap: new THREE.Texture( ), - * rotation: , - * sizeAttenuation: - * } - */ - - class SpriteMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'SpriteMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.alphaMap = null; - - this.rotation = 0; - - this.sizeAttenuation = true; - - this.transparent = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.rotation = source.rotation; - - this.sizeAttenuation = source.sizeAttenuation; - - return this; - - } - - } - - SpriteMaterial.prototype.isSpriteMaterial = true; - - let _geometry; - - const _intersectPoint = /*@__PURE__*/ new Vector3(); - const _worldScale = /*@__PURE__*/ new Vector3(); - const _mvPosition = /*@__PURE__*/ new Vector3(); - - const _alignedPosition = /*@__PURE__*/ new Vector2(); - const _rotatedPosition = /*@__PURE__*/ new Vector2(); - const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); - - const _vA = /*@__PURE__*/ new Vector3(); - const _vB = /*@__PURE__*/ new Vector3(); - const _vC = /*@__PURE__*/ new Vector3(); - - const _uvA = /*@__PURE__*/ new Vector2(); - const _uvB = /*@__PURE__*/ new Vector2(); - const _uvC = /*@__PURE__*/ new Vector2(); - - class Sprite extends Object3D { - - constructor( material ) { - - super(); - - this.type = 'Sprite'; - - if ( _geometry === undefined ) { - - _geometry = new BufferGeometry(); - - const float32Array = new Float32Array( [ - - 0.5, - 0.5, 0, 0, 0, - 0.5, - 0.5, 0, 1, 0, - 0.5, 0.5, 0, 1, 1, - - 0.5, 0.5, 0, 0, 1 - ] ); - - const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); - - _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); - _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); - _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); - - } - - this.geometry = _geometry; - this.material = ( material !== undefined ) ? material : new SpriteMaterial(); - - this.center = new Vector2( 0.5, 0.5 ); - - } - - raycast( raycaster, intersects ) { - - if ( raycaster.camera === null ) { - - console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); - - } - - _worldScale.setFromMatrixScale( this.matrixWorld ); - - _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); - this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); - - _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); - - if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { - - _worldScale.multiplyScalar( - _mvPosition.z ); - - } - - const rotation = this.material.rotation; - let sin, cos; - - if ( rotation !== 0 ) { - - cos = Math.cos( rotation ); - sin = Math.sin( rotation ); - - } - - const center = this.center; - - transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - - _uvA.set( 0, 0 ); - _uvB.set( 1, 0 ); - _uvC.set( 1, 1 ); - - // check first triangle - let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint ); - - if ( intersect === null ) { - - // check second triangle - transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - _uvB.set( 0, 1 ); - - intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint ); - if ( intersect === null ) { - - return; - - } - - } - - const distance = raycaster.ray.origin.distanceTo( _intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { - - distance: distance, - point: _intersectPoint.clone(), - uv: Triangle.getUV( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ), - face: null, - object: this - - } ); - - } - - copy( source ) { - - super.copy( source ); - - if ( source.center !== undefined ) this.center.copy( source.center ); - - this.material = source.material; - - return this; - - } - - } - - Sprite.prototype.isSprite = true; - - function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { - - // compute position in camera space - _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); - - // to check if rotation is not zero - if ( sin !== undefined ) { - - _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); - _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); - - } else { - - _rotatedPosition.copy( _alignedPosition ); - - } - - - vertexPosition.copy( mvPosition ); - vertexPosition.x += _rotatedPosition.x; - vertexPosition.y += _rotatedPosition.y; - - // transform to world space - vertexPosition.applyMatrix4( _viewWorldMatrix ); - - } - - const _v1$2 = /*@__PURE__*/ new Vector3(); - const _v2$1 = /*@__PURE__*/ new Vector3(); - - class LOD extends Object3D { - - constructor() { - - super(); - - this._currentLevel = 0; - - this.type = 'LOD'; - - Object.defineProperties( this, { - levels: { - enumerable: true, - value: [] - }, - isLOD: { - value: true, - } - } ); - - this.autoUpdate = true; - - } - - copy( source ) { - - super.copy( source, false ); - - const levels = source.levels; - - for ( let i = 0, l = levels.length; i < l; i ++ ) { - - const level = levels[ i ]; - - this.addLevel( level.object.clone(), level.distance ); - - } - - this.autoUpdate = source.autoUpdate; - - return this; - - } - - addLevel( object, distance = 0 ) { - - distance = Math.abs( distance ); - - const levels = this.levels; - - let l; - - for ( l = 0; l < levels.length; l ++ ) { - - if ( distance < levels[ l ].distance ) { - - break; - - } - - } - - levels.splice( l, 0, { distance: distance, object: object } ); - - this.add( object ); - - return this; - - } - - getCurrentLevel() { - - return this._currentLevel; - - } - - getObjectForDistance( distance ) { - - const levels = this.levels; - - if ( levels.length > 0 ) { - - let i, l; - - for ( i = 1, l = levels.length; i < l; i ++ ) { - - if ( distance < levels[ i ].distance ) { - - break; - - } - - } - - return levels[ i - 1 ].object; - - } - - return null; - - } - - raycast( raycaster, intersects ) { - - const levels = this.levels; - - if ( levels.length > 0 ) { - - _v1$2.setFromMatrixPosition( this.matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( _v1$2 ); - - this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - - } - - } - - update( camera ) { - - const levels = this.levels; - - if ( levels.length > 1 ) { - - _v1$2.setFromMatrixPosition( camera.matrixWorld ); - _v2$1.setFromMatrixPosition( this.matrixWorld ); - - const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom; - - levels[ 0 ].object.visible = true; - - let i, l; - - for ( i = 1, l = levels.length; i < l; i ++ ) { - - if ( distance >= levels[ i ].distance ) { - - levels[ i - 1 ].object.visible = false; - levels[ i ].object.visible = true; - - } else { - - break; - - } - - } - - this._currentLevel = i - 1; - - for ( ; i < l; i ++ ) { - - levels[ i ].object.visible = false; - - } - - } - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - if ( this.autoUpdate === false ) data.object.autoUpdate = false; - - data.object.levels = []; - - const levels = this.levels; - - for ( let i = 0, l = levels.length; i < l; i ++ ) { - - const level = levels[ i ]; - - data.object.levels.push( { - object: level.object.uuid, - distance: level.distance - } ); - - } - - return data; - - } - - } - - const _basePosition = /*@__PURE__*/ new Vector3(); - - const _skinIndex = /*@__PURE__*/ new Vector4(); - const _skinWeight = /*@__PURE__*/ new Vector4(); - - const _vector$5 = /*@__PURE__*/ new Vector3(); - const _matrix = /*@__PURE__*/ new Matrix4(); - - class SkinnedMesh extends Mesh { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.type = 'SkinnedMesh'; - - this.bindMode = 'attached'; - this.bindMatrix = new Matrix4(); - this.bindMatrixInverse = new Matrix4(); - - } - - copy( source ) { - - super.copy( source ); - - this.bindMode = source.bindMode; - this.bindMatrix.copy( source.bindMatrix ); - this.bindMatrixInverse.copy( source.bindMatrixInverse ); - - this.skeleton = source.skeleton; - - return this; - - } - - bind( skeleton, bindMatrix ) { - - this.skeleton = skeleton; - - if ( bindMatrix === undefined ) { - - this.updateMatrixWorld( true ); - - this.skeleton.calculateInverses(); - - bindMatrix = this.matrixWorld; - - } - - this.bindMatrix.copy( bindMatrix ); - this.bindMatrixInverse.copy( bindMatrix ).invert(); - - } - - pose() { - - this.skeleton.pose(); - - } - - normalizeSkinWeights() { - - const vector = new Vector4(); - - const skinWeight = this.geometry.attributes.skinWeight; - - for ( let i = 0, l = skinWeight.count; i < l; i ++ ) { - - vector.x = skinWeight.getX( i ); - vector.y = skinWeight.getY( i ); - vector.z = skinWeight.getZ( i ); - vector.w = skinWeight.getW( i ); - - const scale = 1.0 / vector.manhattanLength(); - - if ( scale !== Infinity ) { - - vector.multiplyScalar( scale ); - - } else { - - vector.set( 1, 0, 0, 0 ); // do something reasonable - - } - - skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); - - } - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - if ( this.bindMode === 'attached' ) { - - this.bindMatrixInverse.copy( this.matrixWorld ).invert(); - - } else if ( this.bindMode === 'detached' ) { - - this.bindMatrixInverse.copy( this.bindMatrix ).invert(); - - } else { - - console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); - - } - - } - - boneTransform( index, target ) { - - const skeleton = this.skeleton; - const geometry = this.geometry; - - _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); - _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); - - _basePosition.fromBufferAttribute( geometry.attributes.position, index ).applyMatrix4( this.bindMatrix ); - - target.set( 0, 0, 0 ); - - for ( let i = 0; i < 4; i ++ ) { - - const weight = _skinWeight.getComponent( i ); - - if ( weight !== 0 ) { - - const boneIndex = _skinIndex.getComponent( i ); - - _matrix.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); - - target.addScaledVector( _vector$5.copy( _basePosition ).applyMatrix4( _matrix ), weight ); - - } - - } - - return target.applyMatrix4( this.bindMatrixInverse ); - - } - - } - - SkinnedMesh.prototype.isSkinnedMesh = true; - - class Bone extends Object3D { - - constructor() { - - super(); - - this.type = 'Bone'; - - } - - } - - Bone.prototype.isBone = true; - - class DataTexture extends Texture { - - constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, encoding ) { - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - - this.image = { data: data, width: width, height: height }; - - this.magFilter = magFilter; - this.minFilter = minFilter; - - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; - - this.needsUpdate = true; - - } - - } - - DataTexture.prototype.isDataTexture = true; - - const _offsetMatrix = /*@__PURE__*/ new Matrix4(); - const _identityMatrix = /*@__PURE__*/ new Matrix4(); - - class Skeleton { - - constructor( bones = [], boneInverses = [] ) { - - this.uuid = generateUUID(); - - this.bones = bones.slice( 0 ); - this.boneInverses = boneInverses; - this.boneMatrices = null; - - this.boneTexture = null; - this.boneTextureSize = 0; - - this.frame = - 1; - - this.init(); - - } - - init() { - - const bones = this.bones; - const boneInverses = this.boneInverses; - - this.boneMatrices = new Float32Array( bones.length * 16 ); - - // calculate inverse bone matrices if necessary - - if ( boneInverses.length === 0 ) { - - this.calculateInverses(); - - } else { - - // handle special case - - if ( bones.length !== boneInverses.length ) { - - console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' ); - - this.boneInverses = []; - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - this.boneInverses.push( new Matrix4() ); - - } - - } - - } - - } - - calculateInverses() { - - this.boneInverses.length = 0; - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const inverse = new Matrix4(); - - if ( this.bones[ i ] ) { - - inverse.copy( this.bones[ i ].matrixWorld ).invert(); - - } - - this.boneInverses.push( inverse ); - - } - - } - - pose() { - - // recover the bind-time world matrices - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone ) { - - bone.matrixWorld.copy( this.boneInverses[ i ] ).invert(); - - } - - } - - // compute the local matrices, positions, rotations and scales - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone ) { - - if ( bone.parent && bone.parent.isBone ) { - - bone.matrix.copy( bone.parent.matrixWorld ).invert(); - bone.matrix.multiply( bone.matrixWorld ); - - } else { - - bone.matrix.copy( bone.matrixWorld ); - - } - - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - - } - - } - - } - - update() { - - const bones = this.bones; - const boneInverses = this.boneInverses; - const boneMatrices = this.boneMatrices; - const boneTexture = this.boneTexture; - - // flatten bone matrices to array - - for ( let i = 0, il = bones.length; i < il; i ++ ) { - - // compute the offset between the current and the original transform - - const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix; - - _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); - _offsetMatrix.toArray( boneMatrices, i * 16 ); - - } - - if ( boneTexture !== null ) { - - boneTexture.needsUpdate = true; - - } - - } - - clone() { - - return new Skeleton( this.bones, this.boneInverses ); - - } - - computeBoneTexture() { - - // layout (1 matrix = 4 pixels) - // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) - // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) - // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) - // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) - // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) - - let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix - size = ceilPowerOfTwo( size ); - size = Math.max( size, 4 ); - - const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - boneMatrices.set( this.boneMatrices ); // copy current values - - const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); - - this.boneMatrices = boneMatrices; - this.boneTexture = boneTexture; - this.boneTextureSize = size; - - return this; - - } - - getBoneByName( name ) { - - for ( let i = 0, il = this.bones.length; i < il; i ++ ) { - - const bone = this.bones[ i ]; - - if ( bone.name === name ) { - - return bone; - - } - - } - - return undefined; - - } - - dispose( ) { - - if ( this.boneTexture !== null ) { - - this.boneTexture.dispose(); - - this.boneTexture = null; - - } - - } - - fromJSON( json, bones ) { - - this.uuid = json.uuid; - - for ( let i = 0, l = json.bones.length; i < l; i ++ ) { - - const uuid = json.bones[ i ]; - let bone = bones[ uuid ]; - - if ( bone === undefined ) { - - console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid ); - bone = new Bone(); - - } - - this.bones.push( bone ); - this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) ); - - } - - this.init(); - - return this; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.5, - type: 'Skeleton', - generator: 'Skeleton.toJSON' - }, - bones: [], - boneInverses: [] - }; - - data.uuid = this.uuid; - - const bones = this.bones; - const boneInverses = this.boneInverses; - - for ( let i = 0, l = bones.length; i < l; i ++ ) { - - const bone = bones[ i ]; - data.bones.push( bone.uuid ); - - const boneInverse = boneInverses[ i ]; - data.boneInverses.push( boneInverse.toArray() ); - - } - - return data; - - } - - } - - class InstancedBufferAttribute extends BufferAttribute { - - constructor( array, itemSize, normalized, meshPerAttribute = 1 ) { - - if ( typeof normalized === 'number' ) { - - meshPerAttribute = normalized; - - normalized = false; - - console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' ); - - } - - super( array, itemSize, normalized ); - - this.meshPerAttribute = meshPerAttribute; - - } - - copy( source ) { - - super.copy( source ); - - this.meshPerAttribute = source.meshPerAttribute; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.meshPerAttribute = this.meshPerAttribute; - - data.isInstancedBufferAttribute = true; - - return data; - - } - - } - - InstancedBufferAttribute.prototype.isInstancedBufferAttribute = true; - - const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); - const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); - - const _instanceIntersects = []; - - const _mesh = /*@__PURE__*/ new Mesh(); - - class InstancedMesh extends Mesh { - - constructor( geometry, material, count ) { - - super( geometry, material ); - - this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 ); - this.instanceColor = null; - - this.count = count; - - this.frustumCulled = false; - - } - - copy( source ) { - - super.copy( source ); - - this.instanceMatrix.copy( source.instanceMatrix ); - - if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone(); - - this.count = source.count; - - return this; - - } - - getColorAt( index, color ) { - - color.fromArray( this.instanceColor.array, index * 3 ); - - } - - getMatrixAt( index, matrix ) { - - matrix.fromArray( this.instanceMatrix.array, index * 16 ); - - } - - raycast( raycaster, intersects ) { - - const matrixWorld = this.matrixWorld; - const raycastTimes = this.count; - - _mesh.geometry = this.geometry; - _mesh.material = this.material; - - if ( _mesh.material === undefined ) return; - - for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { - - // calculate the world matrix for each instance - - this.getMatrixAt( instanceId, _instanceLocalMatrix ); - - _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); - - // the mesh represents this single instance - - _mesh.matrixWorld = _instanceWorldMatrix; - - _mesh.raycast( raycaster, _instanceIntersects ); - - // process the result of raycast - - for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) { - - const intersect = _instanceIntersects[ i ]; - intersect.instanceId = instanceId; - intersect.object = this; - intersects.push( intersect ); - - } - - _instanceIntersects.length = 0; - - } - - } - - setColorAt( index, color ) { - - if ( this.instanceColor === null ) { - - this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 ); - - } - - color.toArray( this.instanceColor.array, index * 3 ); - - } - - setMatrixAt( index, matrix ) { - - matrix.toArray( this.instanceMatrix.array, index * 16 ); - - } - - updateMorphTargets() { - - } - - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - - } - - InstancedMesh.prototype.isInstancedMesh = true; - - /** - * parameters = { - * color: , - * opacity: , - * - * linewidth: , - * linecap: "round", - * linejoin: "round" - * } - */ - - class LineBasicMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'LineBasicMaterial'; - - this.color = new Color( 0xffffff ); - - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; - - this.setValues( parameters ); - - } - - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.linewidth = source.linewidth; - this.linecap = source.linecap; - this.linejoin = source.linejoin; - - return this; - - } - - } - - LineBasicMaterial.prototype.isLineBasicMaterial = true; - - const _start$1 = /*@__PURE__*/ new Vector3(); - const _end$1 = /*@__PURE__*/ new Vector3(); - const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); - const _ray$1 = /*@__PURE__*/ new Ray(); - const _sphere$1 = /*@__PURE__*/ new Sphere(); - - class Line extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { - - super(); - - this.type = 'Line'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source ) { - - super.copy( source ); - - this.material = source.material; - this.geometry = source.geometry; - - return this; - - } - - computeLineDistances() { - - const geometry = this.geometry; - - if ( geometry.isBufferGeometry ) { - - // we assume non-indexed geometry - - if ( geometry.index === null ) { - - const positionAttribute = geometry.attributes.position; - const lineDistances = [ 0 ]; - - for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { - - _start$1.fromBufferAttribute( positionAttribute, i - 1 ); - _end$1.fromBufferAttribute( positionAttribute, i ); - - lineDistances[ i ] = lineDistances[ i - 1 ]; - lineDistances[ i ] += _start$1.distanceTo( _end$1 ); - - } - - geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - - } else { - - console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - - } - - } else if ( geometry.isGeometry ) { - - console.error( 'THREE.Line.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - - } - - return this; - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const matrixWorld = this.matrixWorld; - const threshold = raycaster.params.Line.threshold; - const drawRange = geometry.drawRange; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere$1.copy( geometry.boundingSphere ); - _sphere$1.applyMatrix4( matrixWorld ); - _sphere$1.radius += threshold; - - if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; - - // - - _inverseMatrix$1.copy( matrixWorld ).invert(); - _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); - - const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - const localThresholdSq = localThreshold * localThreshold; - - const vStart = new Vector3(); - const vEnd = new Vector3(); - const interSegment = new Vector3(); - const interRay = new Vector3(); - const step = this.isLineSegments ? 2 : 1; - - if ( geometry.isBufferGeometry ) { - - const index = geometry.index; - const attributes = geometry.attributes; - const positionAttribute = attributes.position; - - if ( index !== null ) { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end - 1; i < l; i += step ) { - - const a = index.getX( i ); - const b = index.getX( i + 1 ); - - vStart.fromBufferAttribute( positionAttribute, a ); - vEnd.fromBufferAttribute( positionAttribute, b ); - - const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - - if ( distSq > localThresholdSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - const distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end - 1; i < l; i += step ) { - - vStart.fromBufferAttribute( positionAttribute, i ); - vEnd.fromBufferAttribute( positionAttribute, i + 1 ); - - const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - - if ( distSq > localThresholdSq ) continue; - - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - - const distance = raycaster.ray.origin.distanceTo( interRay ); - - if ( distance < raycaster.near || distance > raycaster.far ) continue; - - intersects.push( { - - distance: distance, - // What do we want? intersection point on the ray or on the segment?? - // point: raycaster.ray.at( distance ), - point: interSegment.clone().applyMatrix4( this.matrixWorld ), - index: i, - face: null, - faceIndex: null, - object: this - - } ); - - } - - } - - } else if ( geometry.isGeometry ) { - - console.error( 'THREE.Line.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - - } - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - if ( geometry.isBufferGeometry ) { - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } else { - - const morphTargets = geometry.morphTargets; - - if ( morphTargets !== undefined && morphTargets.length > 0 ) { - - console.error( 'THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' ); - - } - - } - - } - - } - - Line.prototype.isLine = true; - - const _start = /*@__PURE__*/ new Vector3(); - const _end = /*@__PURE__*/ new Vector3(); - - class LineSegments extends Line { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.type = 'LineSegments'; - - } - - computeLineDistances() { - - const geometry = this.geometry; - - if ( geometry.isBufferGeometry ) { - - // we assume non-indexed geometry - - if ( geometry.index === null ) { - - const positionAttribute = geometry.attributes.position; - const lineDistances = []; - - for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) { - - _start.fromBufferAttribute( positionAttribute, i ); - _end.fromBufferAttribute( positionAttribute, i + 1 ); - - lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; - lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end ); - - } - - geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - - } else { - - console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - - } - - } else if ( geometry.isGeometry ) { - - console.error( 'THREE.LineSegments.computeLineDistances() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - - } - - return this; - - } - - } - - LineSegments.prototype.isLineSegments = true; - - class LineLoop extends Line { - - constructor( geometry, material ) { - - super( geometry, material ); - - this.type = 'LineLoop'; - - } - - } - - LineLoop.prototype.isLineLoop = true; - - /** - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * alphaMap: new THREE.Texture( ), - * - * size: , - * sizeAttenuation: - * - * } - */ - - class PointsMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'PointsMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - - this.alphaMap = null; - - this.size = 1; - this.sizeAttenuation = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.alphaMap = source.alphaMap; - - this.size = source.size; - this.sizeAttenuation = source.sizeAttenuation; - - return this; - - } - - } - - PointsMaterial.prototype.isPointsMaterial = true; - - const _inverseMatrix = /*@__PURE__*/ new Matrix4(); - const _ray = /*@__PURE__*/ new Ray(); - const _sphere = /*@__PURE__*/ new Sphere(); - const _position$2 = /*@__PURE__*/ new Vector3(); - - class Points extends Object3D { - - constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) { - - super(); - - this.type = 'Points'; - - this.geometry = geometry; - this.material = material; - - this.updateMorphTargets(); - - } - - copy( source ) { - - super.copy( source ); - - this.material = source.material; - this.geometry = source.geometry; - - return this; - - } - - raycast( raycaster, intersects ) { - - const geometry = this.geometry; - const matrixWorld = this.matrixWorld; - const threshold = raycaster.params.Points.threshold; - const drawRange = geometry.drawRange; - - // Checking boundingSphere distance to ray - - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - - _sphere.copy( geometry.boundingSphere ); - _sphere.applyMatrix4( matrixWorld ); - _sphere.radius += threshold; - - if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; - - // - - _inverseMatrix.copy( matrixWorld ).invert(); - _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); - - const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - const localThresholdSq = localThreshold * localThreshold; - - if ( geometry.isBufferGeometry ) { - - const index = geometry.index; - const attributes = geometry.attributes; - const positionAttribute = attributes.position; - - if ( index !== null ) { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, il = end; i < il; i ++ ) { - - const a = index.getX( i ); - - _position$2.fromBufferAttribute( positionAttribute, a ); - - testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); - - } - - } else { - - const start = Math.max( 0, drawRange.start ); - const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - - for ( let i = start, l = end; i < l; i ++ ) { - - _position$2.fromBufferAttribute( positionAttribute, i ); - - testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this ); - - } - - } - - } else { - - console.error( 'THREE.Points.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - - } - - } - - updateMorphTargets() { - - const geometry = this.geometry; - - if ( geometry.isBufferGeometry ) { - - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); - - if ( keys.length > 0 ) { - - const morphAttribute = morphAttributes[ keys[ 0 ] ]; - - if ( morphAttribute !== undefined ) { - - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; - - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - - const name = morphAttribute[ m ].name || String( m ); - - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; - - } - - } - - } - - } else { - - const morphTargets = geometry.morphTargets; - - if ( morphTargets !== undefined && morphTargets.length > 0 ) { - - console.error( 'THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' ); - - } - - } - - } - - } - - Points.prototype.isPoints = true; - - function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { - - const rayPointDistanceSq = _ray.distanceSqToPoint( point ); - - if ( rayPointDistanceSq < localThresholdSq ) { - - const intersectPoint = new Vector3(); - - _ray.closestPointToPoint( point, intersectPoint ); - intersectPoint.applyMatrix4( matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( intersectPoint ); - - if ( distance < raycaster.near || distance > raycaster.far ) return; - - intersects.push( { - - distance: distance, - distanceToRay: Math.sqrt( rayPointDistanceSq ), - point: intersectPoint, - index: index, - face: null, - object: object - - } ); - - } - - } - - class VideoTexture extends Texture { - - constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.format = format !== undefined ? format : RGBFormat; - - this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; - this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; - - this.generateMipmaps = false; - - const scope = this; - - function updateVideo() { - - scope.needsUpdate = true; - video.requestVideoFrameCallback( updateVideo ); - - } - - if ( 'requestVideoFrameCallback' in video ) { - - video.requestVideoFrameCallback( updateVideo ); - - } - - } - - clone() { - - return new this.constructor( this.image ).copy( this ); - - } - - update() { - - const video = this.image; - const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; - - if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { - - this.needsUpdate = true; - - } - - } - - } - - VideoTexture.prototype.isVideoTexture = true; - - class CompressedTexture extends Texture { - - constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; - - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) - - this.flipY = false; - - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files - - this.generateMipmaps = false; - - } - - } - - CompressedTexture.prototype.isCompressedTexture = true; - - class CanvasTexture extends Texture { - - constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - - super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.needsUpdate = true; - - } - - } - - CanvasTexture.prototype.isCanvasTexture = true; - - class DepthTexture extends Texture { - - constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - - format = format !== undefined ? format : DepthFormat; - - if ( format !== DepthFormat && format !== DepthStencilFormat ) { - - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); - - } - - if ( type === undefined && format === DepthFormat ) type = UnsignedShortType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.image = { width: width, height: height }; - - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - - this.flipY = false; - this.generateMipmaps = false; - - } - - - } - - DepthTexture.prototype.isDepthTexture = true; - - class CircleGeometry extends BufferGeometry { - - constructor( radius = 1, segments = 8, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - - this.type = 'CircleGeometry'; - - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - segments = Math.max( 3, segments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const vertex = new Vector3(); - const uv = new Vector2(); - - // center point - - vertices.push( 0, 0, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( 0.5, 0.5 ); - - for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { - - const segment = thetaStart + s / segments * thetaLength; - - // vertex - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, 0, 1 ); - - // uvs - - uv.x = ( vertices[ i ] / radius + 1 ) / 2; - uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; - - uvs.push( uv.x, uv.y ); - - } - - // indices - - for ( let i = 1; i <= segments; i ++ ) { - - indices.push( i, i + 1, 0 ); - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - static fromJSON( data ) { - - return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); - - } - - } - - class CylinderGeometry extends BufferGeometry { - - constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - this.type = 'CylinderGeometry'; - - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - const scope = this; - - radialSegments = Math.floor( radialSegments ); - heightSegments = Math.floor( heightSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let index = 0; - const indexArray = []; - const halfHeight = height / 2; - let groupStart = 0; - - // generate geometry - - generateTorso(); - - if ( openEnded === false ) { - - if ( radiusTop > 0 ) generateCap( true ); - if ( radiusBottom > 0 ) generateCap( false ); - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - function generateTorso() { - - const normal = new Vector3(); - const vertex = new Vector3(); - - let groupCount = 0; - - // this will be used to calculate the normal - const slope = ( radiusBottom - radiusTop ) / height; - - // generate vertices, normals and uvs - - for ( let y = 0; y <= heightSegments; y ++ ) { - - const indexRow = []; - - const v = y / heightSegments; - - // calculate the radius of the current row - - const radius = v * ( radiusBottom - radiusTop ) + radiusTop; - - for ( let x = 0; x <= radialSegments; x ++ ) { - - const u = x / radialSegments; - - const theta = u * thetaLength + thetaStart; - - const sinTheta = Math.sin( theta ); - const cosTheta = Math.cos( theta ); - - // vertex - - vertex.x = radius * sinTheta; - vertex.y = - v * height + halfHeight; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normal.set( sinTheta, slope, cosTheta ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u, 1 - v ); - - // save index of vertex in respective row - - indexRow.push( index ++ ); - - } - - // now save vertices of the row in our index array - - indexArray.push( indexRow ); - - } - - // generate indices - - for ( let x = 0; x < radialSegments; x ++ ) { - - for ( let y = 0; y < heightSegments; y ++ ) { - - // we use the index array to access the correct indices - - const a = indexArray[ y ][ x ]; - const b = indexArray[ y + 1 ][ x ]; - const c = indexArray[ y + 1 ][ x + 1 ]; - const d = indexArray[ y ][ x + 1 ]; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - // update group counter - - groupCount += 6; - - } - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, 0 ); - - // calculate new start value for groups - - groupStart += groupCount; - - } - - function generateCap( top ) { - - // save the index of the first center vertex - const centerIndexStart = index; - - const uv = new Vector2(); - const vertex = new Vector3(); - - let groupCount = 0; - - const radius = ( top === true ) ? radiusTop : radiusBottom; - const sign = ( top === true ) ? 1 : - 1; - - // first we generate the center vertex data of the cap. - // because the geometry needs one set of uvs per face, - // we must generate a center vertex per face/segment - - for ( let x = 1; x <= radialSegments; x ++ ) { - - // vertex - - vertices.push( 0, halfHeight * sign, 0 ); - - // normal - - normals.push( 0, sign, 0 ); - - // uv - - uvs.push( 0.5, 0.5 ); - - // increase index - - index ++; - - } - - // save the index of the last center vertex - const centerIndexEnd = index; - - // now we generate the surrounding vertices, normals and uvs - - for ( let x = 0; x <= radialSegments; x ++ ) { - - const u = x / radialSegments; - const theta = u * thetaLength + thetaStart; - - const cosTheta = Math.cos( theta ); - const sinTheta = Math.sin( theta ); - - // vertex - - vertex.x = radius * sinTheta; - vertex.y = halfHeight * sign; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, sign, 0 ); - - // uv - - uv.x = ( cosTheta * 0.5 ) + 0.5; - uv.y = ( sinTheta * 0.5 * sign ) + 0.5; - uvs.push( uv.x, uv.y ); - - // increase index - - index ++; - - } - - // generate indices - - for ( let x = 0; x < radialSegments; x ++ ) { - - const c = centerIndexStart + x; - const i = centerIndexEnd + x; - - if ( top === true ) { - - // face top - - indices.push( i, i + 1, c ); - - } else { - - // face bottom - - indices.push( i + 1, i, c ); - - } - - groupCount += 3; - - } - - // add a group to the geometry. this will ensure multi material support - - scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); - - // calculate new start value for groups - - groupStart += groupCount; - - } - - } - - static fromJSON( data ) { - - return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); - - } - - } - - class ConeGeometry extends CylinderGeometry { - - constructor( radius = 1, height = 1, radialSegments = 8, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - - this.type = 'ConeGeometry'; - - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - } - - static fromJSON( data ) { - - return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); - - } - - } - - class PolyhedronGeometry extends BufferGeometry { - - constructor( vertices, indices, radius = 1, detail = 0 ) { - - super(); - - this.type = 'PolyhedronGeometry'; - - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; - - // default buffer data - - const vertexBuffer = []; - const uvBuffer = []; - - // the subdivision creates the vertex buffer data - - subdivide( detail ); - - // all vertices should lie on a conceptual sphere with a given radius - - applyRadius( radius ); - - // finally, create the uv data - - generateUVs(); - - // build non-indexed geometry - - this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); - - if ( detail === 0 ) { - - this.computeVertexNormals(); // flat normals - - } else { - - this.normalizeNormals(); // smooth normals - - } - - // helper functions - - function subdivide( detail ) { - - const a = new Vector3(); - const b = new Vector3(); - const c = new Vector3(); - - // iterate over all faces and apply a subdivison with the given detail value - - for ( let i = 0; i < indices.length; i += 3 ) { - - // get the vertices of the face - - getVertexByIndex( indices[ i + 0 ], a ); - getVertexByIndex( indices[ i + 1 ], b ); - getVertexByIndex( indices[ i + 2 ], c ); - - // perform subdivision - - subdivideFace( a, b, c, detail ); - - } - - } - - function subdivideFace( a, b, c, detail ) { - - const cols = detail + 1; - - // we use this multidimensional array as a data structure for creating the subdivision - - const v = []; - - // construct all of the vertices for this subdivision - - for ( let i = 0; i <= cols; i ++ ) { - - v[ i ] = []; - - const aj = a.clone().lerp( c, i / cols ); - const bj = b.clone().lerp( c, i / cols ); - - const rows = cols - i; - - for ( let j = 0; j <= rows; j ++ ) { - - if ( j === 0 && i === cols ) { - - v[ i ][ j ] = aj; - - } else { - - v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); - - } - - } - - } - - // construct all of the faces - - for ( let i = 0; i < cols; i ++ ) { - - for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { - - const k = Math.floor( j / 2 ); - - if ( j % 2 === 0 ) { - - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - pushVertex( v[ i ][ k ] ); - - } else { - - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - - } - - } - - } - - } - - function applyRadius( radius ) { - - const vertex = new Vector3(); - - // iterate over the entire buffer and apply the radius to each vertex - - for ( let i = 0; i < vertexBuffer.length; i += 3 ) { - - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; - - vertex.normalize().multiplyScalar( radius ); - - vertexBuffer[ i + 0 ] = vertex.x; - vertexBuffer[ i + 1 ] = vertex.y; - vertexBuffer[ i + 2 ] = vertex.z; - - } - - } - - function generateUVs() { - - const vertex = new Vector3(); - - for ( let i = 0; i < vertexBuffer.length; i += 3 ) { - - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; - - const u = azimuth( vertex ) / 2 / Math.PI + 0.5; - const v = inclination( vertex ) / Math.PI + 0.5; - uvBuffer.push( u, 1 - v ); - - } - - correctUVs(); - - correctSeam(); - - } - - function correctSeam() { - - // handle case when face straddles the seam, see #3269 - - for ( let i = 0; i < uvBuffer.length; i += 6 ) { - - // uv data of a single face - - const x0 = uvBuffer[ i + 0 ]; - const x1 = uvBuffer[ i + 2 ]; - const x2 = uvBuffer[ i + 4 ]; - - const max = Math.max( x0, x1, x2 ); - const min = Math.min( x0, x1, x2 ); - - // 0.9 is somewhat arbitrary - - if ( max > 0.9 && min < 0.1 ) { - - if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; - if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; - if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; - - } - - } - - } - - function pushVertex( vertex ) { - - vertexBuffer.push( vertex.x, vertex.y, vertex.z ); - - } - - function getVertexByIndex( index, vertex ) { - - const stride = index * 3; - - vertex.x = vertices[ stride + 0 ]; - vertex.y = vertices[ stride + 1 ]; - vertex.z = vertices[ stride + 2 ]; - - } - - function correctUVs() { - - const a = new Vector3(); - const b = new Vector3(); - const c = new Vector3(); - - const centroid = new Vector3(); - - const uvA = new Vector2(); - const uvB = new Vector2(); - const uvC = new Vector2(); - - for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { - - a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); - b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); - c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); - - uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); - uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); - uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); - - centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); - - const azi = azimuth( centroid ); - - correctUV( uvA, j + 0, a, azi ); - correctUV( uvB, j + 2, b, azi ); - correctUV( uvC, j + 4, c, azi ); - - } - - } - - function correctUV( uv, stride, vector, azimuth ) { - - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { - - uvBuffer[ stride ] = uv.x - 1; - - } - - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { - - uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; - - } - - } - - // Angle around the Y axis, counter-clockwise when looking from above. - - function azimuth( vector ) { - - return Math.atan2( vector.z, - vector.x ); - - } - - - // Angle above the XZ plane. - - function inclination( vector ) { - - return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - - } - - } - - static fromJSON( data ) { - - return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details ); - - } - - } - - class DodecahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const t = ( 1 + Math.sqrt( 5 ) ) / 2; - const r = 1 / t; - - const vertices = [ - - // (±1, ±1, ±1) - - 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, ±1/φ, ±φ) - 0, - r, - t, 0, - r, t, - 0, r, - t, 0, r, t, - - // (±1/φ, ±φ, 0) - - r, - t, 0, - r, t, 0, - r, - t, 0, r, t, 0, - - // (±φ, 0, ±1/φ) - - t, 0, - r, t, 0, - r, - - t, 0, r, t, 0, r - ]; - - const indices = [ - 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 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'DodecahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new DodecahedronGeometry( data.radius, data.detail ); - - } - - } - - const _v0 = new Vector3(); - const _v1$1 = new Vector3(); - const _normal = new Vector3(); - const _triangle = new Triangle(); - - class EdgesGeometry extends BufferGeometry { - - constructor( geometry, thresholdAngle ) { - - super(); - - this.type = 'EdgesGeometry'; - - this.parameters = { - thresholdAngle: thresholdAngle - }; - - thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; - - if ( geometry.isGeometry === true ) { - - console.error( 'THREE.EdgesGeometry no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - return; - - } - - const precisionPoints = 4; - const precision = Math.pow( 10, precisionPoints ); - const thresholdDot = Math.cos( DEG2RAD * thresholdAngle ); - - const indexAttr = geometry.getIndex(); - const positionAttr = geometry.getAttribute( 'position' ); - const indexCount = indexAttr ? indexAttr.count : positionAttr.count; - - const indexArr = [ 0, 0, 0 ]; - const vertKeys = [ 'a', 'b', 'c' ]; - const hashes = new Array( 3 ); - - const edgeData = {}; - const vertices = []; - for ( let i = 0; i < indexCount; i += 3 ) { - - if ( indexAttr ) { - - indexArr[ 0 ] = indexAttr.getX( i ); - indexArr[ 1 ] = indexAttr.getX( i + 1 ); - indexArr[ 2 ] = indexAttr.getX( i + 2 ); - - } else { - - indexArr[ 0 ] = i; - indexArr[ 1 ] = i + 1; - indexArr[ 2 ] = i + 2; - - } - - const { a, b, c } = _triangle; - a.fromBufferAttribute( positionAttr, indexArr[ 0 ] ); - b.fromBufferAttribute( positionAttr, indexArr[ 1 ] ); - c.fromBufferAttribute( positionAttr, indexArr[ 2 ] ); - _triangle.getNormal( _normal ); - - // create hashes for the edge from the vertices - hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`; - hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`; - hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`; - - // skip degenerate triangles - if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) { - - continue; - - } - - // iterate over every edge - for ( let j = 0; j < 3; j ++ ) { - - // get the first and next vertex making up the edge - const jNext = ( j + 1 ) % 3; - const vecHash0 = hashes[ j ]; - const vecHash1 = hashes[ jNext ]; - const v0 = _triangle[ vertKeys[ j ] ]; - const v1 = _triangle[ vertKeys[ jNext ] ]; - - const hash = `${ vecHash0 }_${ vecHash1 }`; - const reverseHash = `${ vecHash1 }_${ vecHash0 }`; - - if ( reverseHash in edgeData && edgeData[ reverseHash ] ) { - - // if we found a sibling edge add it into the vertex array if - // it meets the angle threshold and delete the edge from the map. - if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) { - - vertices.push( v0.x, v0.y, v0.z ); - vertices.push( v1.x, v1.y, v1.z ); - - } - - edgeData[ reverseHash ] = null; - - } else if ( ! ( hash in edgeData ) ) { - - // if we've already got an edge here then skip adding a new one - edgeData[ hash ] = { - - index0: indexArr[ j ], - index1: indexArr[ jNext ], - normal: _normal.clone(), - - }; - - } - - } - - } - - // iterate over all remaining, unmatched edges and add them to the vertex array - for ( const key in edgeData ) { - - if ( edgeData[ key ] ) { - - const { index0, index1 } = edgeData[ key ]; - _v0.fromBufferAttribute( positionAttr, index0 ); - _v1$1.fromBufferAttribute( positionAttr, index1 ); - - vertices.push( _v0.x, _v0.y, _v0.z ); - vertices.push( _v1$1.x, _v1$1.y, _v1$1.z ); - - } - - } - - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - - } - - } - - /** - * Extensible curve object. - * - * Some common of curve methods: - * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget ) - * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget ) - * .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. - * - **/ - - class Curve { - - constructor() { - - this.type = 'Curve'; - - this.arcLengthDivisions = 200; - - } - - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] - - getPoint( /* t, optionalTarget */ ) { - - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; - - } - - // Get point at relative position in curve according to arc length - // - u [0 .. 1] - - getPointAt( u, optionalTarget ) { - - const t = this.getUtoTmapping( u ); - return this.getPoint( t, optionalTarget ); - - } - - // Get sequence of points using getPoint( t ) - - getPoints( divisions = 5 ) { - - const points = []; - - for ( let d = 0; d <= divisions; d ++ ) { - - points.push( this.getPoint( d / divisions ) ); - - } - - return points; - - } - - // Get sequence of points using getPointAt( u ) - - getSpacedPoints( divisions = 5 ) { - - const points = []; - - for ( let d = 0; d <= divisions; d ++ ) { - - points.push( this.getPointAt( d / divisions ) ); - - } - - return points; - - } - - // Get total curve arc length - - getLength() { - - const lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; - - } - - // Get list of cumulative segment lengths - - getLengths( divisions = this.arcLengthDivisions ) { - - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { - - return this.cacheArcLengths; - - } - - this.needsUpdate = false; - - const cache = []; - let current, last = this.getPoint( 0 ); - let sum = 0; - - cache.push( 0 ); - - for ( let p = 1; p <= divisions; p ++ ) { - - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; - - } - - this.cacheArcLengths = cache; - - return cache; // { sums: cache, sum: sum }; Sum is in the last element. - - } - - updateArcLengths() { - - this.needsUpdate = true; - this.getLengths(); - - } - - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant - - getUtoTmapping( u, distance ) { - - const arcLengths = this.getLengths(); - - let i = 0; - const il = arcLengths.length; - - let targetArcLength; // The targeted u distance value to get - - if ( distance ) { - - targetArcLength = distance; - - } else { - - targetArcLength = u * arcLengths[ il - 1 ]; - - } - - // binary search for the index with largest value smaller than target u distance - - let low = 0, high = il - 1, comparison; - - while ( low <= high ) { - - i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - - comparison = arcLengths[ i ] - targetArcLength; - - if ( comparison < 0 ) { - - low = i + 1; - - } else if ( comparison > 0 ) { - - high = i - 1; - - } else { - - high = i; - break; - - // DONE - - } - - } - - i = high; - - if ( arcLengths[ i ] === targetArcLength ) { - - return i / ( il - 1 ); - - } - - // we could get finer grain at lengths, or use simple interpolation between two points - - const lengthBefore = arcLengths[ i ]; - const lengthAfter = arcLengths[ i + 1 ]; - - const segmentLength = lengthAfter - lengthBefore; - - // determine where we are between the 'before' and 'after' points - - const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - - // add that fractional amount to t - - const t = ( i + segmentFraction ) / ( il - 1 ); - - return t; - - } - - // Returns a unit vector tangent at t - // In case any sub curve does not implement its tangent derivation, - // 2 points a small delta apart will be used to find its gradient - // which seems to give a reasonable approximation - - getTangent( t, optionalTarget ) { - - const delta = 0.0001; - let t1 = t - delta; - let t2 = t + delta; - - // Capping in case of danger - - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; - - const pt1 = this.getPoint( t1 ); - const pt2 = this.getPoint( t2 ); - - const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); - - tangent.copy( pt2 ).sub( pt1 ).normalize(); - - return tangent; - - } - - getTangentAt( u, optionalTarget ) { - - const t = this.getUtoTmapping( u ); - return this.getTangent( t, optionalTarget ); - - } - - computeFrenetFrames( segments, closed ) { - - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf - - const normal = new Vector3(); - - const tangents = []; - const normals = []; - const binormals = []; - - const vec = new Vector3(); - const mat = new Matrix4(); - - // compute the tangent vectors for each segment on the curve - - for ( let i = 0; i <= segments; i ++ ) { - - const u = i / segments; - - tangents[ i ] = this.getTangentAt( u, new Vector3() ); - tangents[ i ].normalize(); - - } - - // 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(); - let min = Number.MAX_VALUE; - const tx = Math.abs( tangents[ 0 ].x ); - const ty = Math.abs( tangents[ 0 ].y ); - const tz = Math.abs( tangents[ 0 ].z ); - - if ( tx <= min ) { - - min = tx; - normal.set( 1, 0, 0 ); - - } - - if ( ty <= min ) { - - min = ty; - normal.set( 0, 1, 0 ); - - } - - if ( tz <= min ) { - - normal.set( 0, 0, 1 ); - - } - - vec.crossVectors( tangents[ 0 ], normal ).normalize(); - - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); - - - // compute the slowly-varying normal and binormal vectors for each segment on the curve - - for ( let i = 1; i <= segments; i ++ ) { - - normals[ i ] = normals[ i - 1 ].clone(); - - binormals[ i ] = binormals[ i - 1 ].clone(); - - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); - - if ( vec.length() > Number.EPSILON ) { - - vec.normalize(); - - const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors - - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - - } - - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - - if ( closed === true ) { - - let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; - - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - - theta = - theta; - - } - - for ( let i = 1; i <= segments; i ++ ) { - - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); - - } - - } - - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( source ) { - - this.arcLengthDivisions = source.arcLengthDivisions; - - return this; - - } - - toJSON() { - - const data = { - metadata: { - version: 4.5, - type: 'Curve', - generator: 'Curve.toJSON' - } - }; - - data.arcLengthDivisions = this.arcLengthDivisions; - data.type = this.type; - - return data; - - } - - fromJSON( json ) { - - this.arcLengthDivisions = json.arcLengthDivisions; - - return this; - - } - - } - - class EllipseCurve extends Curve { - - constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { - - super(); - - this.type = 'EllipseCurve'; - - this.aX = aX; - this.aY = aY; - - this.xRadius = xRadius; - this.yRadius = yRadius; - - this.aStartAngle = aStartAngle; - this.aEndAngle = aEndAngle; - - this.aClockwise = aClockwise; - - this.aRotation = aRotation; - - } - - getPoint( t, optionalTarget ) { - - const point = optionalTarget || new Vector2(); - - const twoPi = Math.PI * 2; - let deltaAngle = this.aEndAngle - this.aStartAngle; - const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; - - if ( deltaAngle < Number.EPSILON ) { - - if ( samePoints ) { - - deltaAngle = 0; - - } else { - - deltaAngle = twoPi; - - } - - } - - if ( this.aClockwise === true && ! samePoints ) { - - if ( deltaAngle === twoPi ) { - - deltaAngle = - twoPi; - - } else { - - deltaAngle = deltaAngle - twoPi; - - } - - } - - const angle = this.aStartAngle + t * deltaAngle; - let x = this.aX + this.xRadius * Math.cos( angle ); - let y = this.aY + this.yRadius * Math.sin( angle ); - - if ( this.aRotation !== 0 ) { - - const cos = Math.cos( this.aRotation ); - const sin = Math.sin( this.aRotation ); - - const tx = x - this.aX; - const 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; - - } - - return point.set( x, y ); - - } - - copy( source ) { - - super.copy( source ); - - this.aX = source.aX; - this.aY = source.aY; - - this.xRadius = source.xRadius; - this.yRadius = source.yRadius; - - this.aStartAngle = source.aStartAngle; - this.aEndAngle = source.aEndAngle; - - this.aClockwise = source.aClockwise; - - this.aRotation = source.aRotation; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.aX = this.aX; - data.aY = this.aY; - - data.xRadius = this.xRadius; - data.yRadius = this.yRadius; - - data.aStartAngle = this.aStartAngle; - data.aEndAngle = this.aEndAngle; - - data.aClockwise = this.aClockwise; - - data.aRotation = this.aRotation; - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.aX = json.aX; - this.aY = json.aY; - - this.xRadius = json.xRadius; - this.yRadius = json.yRadius; - - this.aStartAngle = json.aStartAngle; - this.aEndAngle = json.aEndAngle; - - this.aClockwise = json.aClockwise; - - this.aRotation = json.aRotation; - - return this; - - } - - } - - EllipseCurve.prototype.isEllipseCurve = true; - - class ArcCurve extends EllipseCurve { - - constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - this.type = 'ArcCurve'; - - } - - } - - ArcCurve.prototype.isArcCurve = true; - - /** - * 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() { - - let 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] - let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; - let 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 ) { - - const t2 = t * t; - const t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; - - } - - }; - - } - - // - - const tmp = new Vector3(); - const px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly(); - - class CatmullRomCurve3 extends Curve { - - constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { - - super(); - - this.type = 'CatmullRomCurve3'; - - this.points = points; - this.closed = closed; - this.curveType = curveType; - this.tension = tension; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const points = this.points; - const l = points.length; - - const p = ( l - ( this.closed ? 0 : 1 ) ) * t; - let intPoint = Math.floor( p ); - let weight = p - intPoint; - - if ( this.closed ) { - - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; - - } else if ( weight === 0 && intPoint === l - 1 ) { - - intPoint = l - 2; - weight = 1; - - } - - let p0, p3; // 4 points (p1 & p2 defined below) - - 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; - - } - - const p1 = points[ intPoint % l ]; - const 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 - const pow = this.curveType === 'chordal' ? 0.5 : 0.25; - let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); - let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); - let 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; - - } - - copy( source ) { - - super.copy( source ); - - this.points = []; - - for ( let i = 0, l = source.points.length; i < l; i ++ ) { - - const point = source.points[ i ]; - - this.points.push( point.clone() ); - - } - - this.closed = source.closed; - this.curveType = source.curveType; - this.tension = source.tension; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.points = []; - - for ( let i = 0, l = this.points.length; i < l; i ++ ) { - - const point = this.points[ i ]; - data.points.push( point.toArray() ); - - } - - data.closed = this.closed; - data.curveType = this.curveType; - data.tension = this.tension; - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.points = []; - - for ( let i = 0, l = json.points.length; i < l; i ++ ) { - - const point = json.points[ i ]; - this.points.push( new Vector3().fromArray( point ) ); - - } - - this.closed = json.closed; - this.curveType = json.curveType; - this.tension = json.tension; - - return this; - - } - - } - - CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; - - /** - * Bezier Curves formulas obtained from - * http://en.wikipedia.org/wiki/Bézier_curve - */ - - function CatmullRom( t, p0, p1, p2, p3 ) { - - const v0 = ( p2 - p0 ) * 0.5; - const v1 = ( p3 - p1 ) * 0.5; - const t2 = t * t; - const t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; - - } - - // - - function QuadraticBezierP0( t, p ) { - - const k = 1 - t; - return k * k * p; - - } - - function QuadraticBezierP1( t, p ) { - - return 2 * ( 1 - t ) * t * p; - - } - - function QuadraticBezierP2( t, p ) { - - return t * t * p; - - } - - function QuadraticBezier( t, p0, p1, p2 ) { - - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); - - } - - // - - function CubicBezierP0( t, p ) { - - const k = 1 - t; - return k * k * k * p; - - } - - function CubicBezierP1( t, p ) { - - const k = 1 - t; - return 3 * k * k * t * p; - - } - - function CubicBezierP2( t, p ) { - - return 3 * ( 1 - t ) * t * t * p; - - } - - function CubicBezierP3( t, p ) { - - return t * t * t * p; - - } - - function CubicBezier$1( t, p0, p1, p2, p3 ) { - - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); - - } - - class CubicBezierCurve extends Curve { - - constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { - - super(); - - this.type = 'CubicBezierCurve'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - point.set( - CubicBezier$1( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier$1( t, v0.y, v1.y, v2.y, v3.y ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); - - return this; - - } - - } - - CubicBezierCurve.prototype.isCubicBezierCurve = true; - - class CubicBezierCurve3 extends Curve { - - constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { - - super(); - - this.type = 'CubicBezierCurve3'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - this.v3 = v3; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - - point.set( - CubicBezier$1( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier$1( t, v0.y, v1.y, v2.y, v3.y ), - CubicBezier$1( t, v0.z, v1.z, v2.z, v3.z ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); - - return this; - - } - - } - - CubicBezierCurve3.prototype.isCubicBezierCurve3 = true; - - class LineCurve extends Curve { - - constructor( v1 = new Vector2(), v2 = new Vector2() ) { - - super(); - - this.type = 'LineCurve'; - - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - 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 - getPointAt( u, optionalTarget ) { - - return this.getPoint( u, optionalTarget ); - - } - - getTangent( t, optionalTarget ) { - - const tangent = optionalTarget || new Vector2(); - - tangent.copy( this.v2 ).sub( this.v1 ).normalize(); - - return tangent; - - } - - copy( source ) { - - super.copy( source ); - - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - - } - - LineCurve.prototype.isLineCurve = true; - - class LineCurve3 extends Curve { - - constructor( v1 = new Vector3(), v2 = new Vector3() ) { - - super(); - - this.type = 'LineCurve3'; - this.isLineCurve3 = true; - - this.v1 = v1; - this.v2 = v2; - - } - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - 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 - getPointAt( u, optionalTarget ) { - - return this.getPoint( u, optionalTarget ); - - } - copy( source ) { - - super.copy( source ); - - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - toJSON() { - - const data = super.toJSON(); - - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - fromJSON( json ) { - - super.fromJSON( json ); - - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - - } - - class QuadraticBezierCurve extends Curve { - - constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { - - super(); - - this.type = 'QuadraticBezierCurve'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const 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 ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - - } - - QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; - - class QuadraticBezierCurve3 extends Curve { - - constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { - - super(); - - this.type = 'QuadraticBezierCurve3'; - - this.v0 = v0; - this.v1 = v1; - this.v2 = v2; - - } - - getPoint( t, optionalTarget = new Vector3() ) { - - const point = optionalTarget; - - const 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; - - } - - copy( source ) { - - super.copy( source ); - - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - - return this; - - } - - } - - QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; - - class SplineCurve extends Curve { - - constructor( points = [] ) { - - super(); - - this.type = 'SplineCurve'; - - this.points = points; - - } - - getPoint( t, optionalTarget = new Vector2() ) { - - const point = optionalTarget; - - const points = this.points; - const p = ( points.length - 1 ) * t; - - const intPoint = Math.floor( p ); - const weight = p - intPoint; - - const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; - const p1 = points[ intPoint ]; - const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; - const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - - point.set( - CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), - CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) - ); - - return point; - - } - - copy( source ) { - - super.copy( source ); - - this.points = []; - - for ( let i = 0, l = source.points.length; i < l; i ++ ) { - - const point = source.points[ i ]; - - this.points.push( point.clone() ); - - } - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.points = []; - - for ( let i = 0, l = this.points.length; i < l; i ++ ) { - - const point = this.points[ i ]; - data.points.push( point.toArray() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.points = []; - - for ( let i = 0, l = json.points.length; i < l; i ++ ) { - - const point = json.points[ i ]; - this.points.push( new Vector2().fromArray( point ) ); - - } - - return this; - - } - - } - - SplineCurve.prototype.isSplineCurve = true; - - var Curves = /*#__PURE__*/Object.freeze({ - __proto__: null, - ArcCurve: ArcCurve, - CatmullRomCurve3: CatmullRomCurve3, - CubicBezierCurve: CubicBezierCurve, - CubicBezierCurve3: CubicBezierCurve3, - EllipseCurve: EllipseCurve, - LineCurve: LineCurve, - LineCurve3: LineCurve3, - QuadraticBezierCurve: QuadraticBezierCurve, - QuadraticBezierCurve3: QuadraticBezierCurve3, - SplineCurve: SplineCurve - }); - - /** - * Port from https://github.com/mapbox/earcut (v2.2.2) - */ - - const Earcut = { - - triangulate: function ( data, holeIndices, dim = 2 ) { - - const hasHoles = holeIndices && holeIndices.length; - const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length; - let outerNode = linkedList( data, 0, outerLen, dim, true ); - const triangles = []; - - if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles; - - let minX, minY, maxX, maxY, x, y, invSize; - - if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); - - // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox - if ( data.length > 80 * dim ) { - - minX = maxX = data[ 0 ]; - minY = maxY = data[ 1 ]; - - for ( let i = dim; i < outerLen; i += dim ) { - - x = data[ i ]; - y = data[ i + 1 ]; - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - - } - - // minX, minY and invSize are later used to transform coords into integers for z-order calculation - invSize = Math.max( maxX - minX, maxY - minY ); - invSize = invSize !== 0 ? 1 / invSize : 0; - - } - - earcutLinked( outerNode, triangles, dim, minX, minY, invSize ); - - return triangles; - - } - - }; - - // create a circular doubly linked list from polygon points in the specified winding order - function linkedList( data, start, end, dim, clockwise ) { - - let i, last; - - if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { - - for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - - } else { - - for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); - - } - - if ( last && equals( last, last.next ) ) { - - removeNode( last ); - last = last.next; - - } - - return last; - - } - - // eliminate colinear or duplicate points - function filterPoints( start, end ) { - - if ( ! start ) return start; - if ( ! end ) end = start; - - let p = start, - again; - do { - - again = false; - - if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { - - removeNode( p ); - p = end = p.prev; - if ( p === p.next ) break; - again = true; - - } else { - - p = p.next; - - } - - } while ( again || p !== end ); - - return end; - - } - - // main ear slicing loop which triangulates a polygon (given as a linked list) - function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { - - if ( ! ear ) return; - - // interlink polygon nodes in z-order - if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); - - let stop = ear, - prev, next; - - // iterate through ears, slicing them one by one - while ( ear.prev !== ear.next ) { - - prev = ear.prev; - next = ear.next; - - if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { - - // cut off the triangle - triangles.push( prev.i / dim ); - triangles.push( ear.i / dim ); - triangles.push( next.i / dim ); - - removeNode( ear ); - - // skipping the next vertex leads to less sliver triangles - ear = next.next; - stop = next.next; - - continue; - - } - - ear = next; - - // if we looped through the whole remaining polygon and can't find any more ears - if ( ear === stop ) { - - // try filtering points and slicing again - if ( ! pass ) { - - earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); - - // if this didn't work, try curing all small self-intersections locally - - } else if ( pass === 1 ) { - - ear = cureLocalIntersections( filterPoints( ear ), triangles, dim ); - earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); - - // as a last resort, try splitting the remaining polygon into two - - } else if ( pass === 2 ) { - - splitEarcut( ear, triangles, dim, minX, minY, invSize ); - - } - - break; - - } - - } - - } - - // check whether a polygon node forms a valid ear with adjacent nodes - function isEar( ear ) { - - const a = ear.prev, - b = ear, - c = ear.next; - - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - - // now make sure we don't have other points inside the potential ear - let p = ear.next.next; - - while ( p !== ear.prev ) { - - if ( pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && - area( p.prev, p, p.next ) >= 0 ) return false; - p = p.next; - - } - - return true; - - } - - function isEarHashed( ear, minX, minY, invSize ) { - - const a = ear.prev, - b = ear, - c = ear.next; - - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear - - // triangle bbox; min & max are calculated like this for speed - const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ), - minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ), - maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ), - maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y ); - - // z-order range for the current triangle bbox; - const minZ = zOrder( minTX, minTY, minX, minY, invSize ), - maxZ = zOrder( maxTX, maxTY, minX, minY, invSize ); - - let p = ear.prevZ, - n = ear.nextZ; - - // look for points inside the triangle in both directions - while ( p && p.z >= minZ && n && n.z <= maxZ ) { - - if ( p !== ear.prev && p !== ear.next && - pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && - area( p.prev, p, p.next ) >= 0 ) return false; - p = p.prevZ; - - if ( n !== ear.prev && n !== ear.next && - pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) && - area( n.prev, n, n.next ) >= 0 ) return false; - n = n.nextZ; - - } - - // look for remaining points in decreasing z-order - while ( p && p.z >= minZ ) { - - if ( p !== ear.prev && p !== ear.next && - pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y ) && - area( p.prev, p, p.next ) >= 0 ) return false; - p = p.prevZ; - - } - - // look for remaining points in increasing z-order - while ( n && n.z <= maxZ ) { - - if ( n !== ear.prev && n !== ear.next && - pointInTriangle( a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y ) && - area( n.prev, n, n.next ) >= 0 ) return false; - n = n.nextZ; - - } - - return true; - - } - - // go through all polygon nodes and cure small local self-intersections - function cureLocalIntersections( start, triangles, dim ) { - - let p = start; - do { - - const a = p.prev, - b = p.next.next; - - if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { - - triangles.push( a.i / dim ); - triangles.push( p.i / dim ); - triangles.push( b.i / dim ); - - // remove two nodes involved - removeNode( p ); - removeNode( p.next ); - - p = start = b; - - } - - p = p.next; - - } while ( p !== start ); - - return filterPoints( p ); - - } - - // try splitting polygon into two and triangulate them independently - function splitEarcut( start, triangles, dim, minX, minY, invSize ) { - - // look for a valid diagonal that divides the polygon into two - let a = start; - do { - - let b = a.next.next; - while ( b !== a.prev ) { - - if ( a.i !== b.i && isValidDiagonal( a, b ) ) { - - // split the polygon in two by the diagonal - let c = splitPolygon( a, b ); - - // filter colinear points around the cuts - a = filterPoints( a, a.next ); - c = filterPoints( c, c.next ); - - // run earcut on each half - earcutLinked( a, triangles, dim, minX, minY, invSize ); - earcutLinked( c, triangles, dim, minX, minY, invSize ); - return; - - } - - b = b.next; - - } - - a = a.next; - - } while ( a !== start ); - - } - - // link every hole into the outer loop, producing a single-ring polygon without holes - function eliminateHoles( data, holeIndices, outerNode, dim ) { - - const queue = []; - let i, len, start, end, list; - - for ( i = 0, len = holeIndices.length; i < len; i ++ ) { - - start = holeIndices[ i ] * dim; - end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length; - list = linkedList( data, start, end, dim, false ); - if ( list === list.next ) list.steiner = true; - queue.push( getLeftmost( list ) ); - - } - - queue.sort( compareX ); - - // process holes from left to right - for ( i = 0; i < queue.length; i ++ ) { - - eliminateHole( queue[ i ], outerNode ); - outerNode = filterPoints( outerNode, outerNode.next ); - - } - - return outerNode; - - } - - function compareX( a, b ) { - - return a.x - b.x; - - } - - // find a bridge between vertices that connects hole with an outer ring and and link it - function eliminateHole( hole, outerNode ) { - - outerNode = findHoleBridge( hole, outerNode ); - if ( outerNode ) { - - const b = splitPolygon( outerNode, hole ); - - // filter collinear points around the cuts - filterPoints( outerNode, outerNode.next ); - filterPoints( b, b.next ); - - } - - } - - // David Eberly's algorithm for finding a bridge between hole and outer polygon - function findHoleBridge( hole, outerNode ) { - - let p = outerNode; - const hx = hole.x; - const hy = hole.y; - let qx = - Infinity, m; - - // find a segment intersected by a ray from the hole's leftmost point to the left; - // segment's endpoint with lesser x will be potential connection point - do { - - if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { - - const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); - if ( x <= hx && x > qx ) { - - qx = x; - if ( x === hx ) { - - if ( hy === p.y ) return p; - if ( hy === p.next.y ) return p.next; - - } - - m = p.x < p.next.x ? p : p.next; - - } - - } - - p = p.next; - - } while ( p !== outerNode ); - - if ( ! m ) return null; - - if ( hx === qx ) return m; // hole touches outer segment; pick leftmost endpoint - - // look for points inside the triangle of hole point, segment intersection and endpoint; - // if there are no points found, we have a valid connection; - // otherwise choose the point of the minimum angle with the ray as connection point - - const stop = m, - mx = m.x, - my = m.y; - let tanMin = Infinity, tan; - - p = m; - - do { - - if ( hx >= p.x && p.x >= mx && hx !== p.x && - pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) { - - tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential - - if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) { - - m = p; - tanMin = tan; - - } - - } - - p = p.next; - - } while ( p !== stop ); - - return m; - - } - - // whether sector in vertex m contains sector in vertex p in the same coordinates - function sectorContainsSector( m, p ) { - - return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0; - - } - - // interlink polygon nodes in z-order - function indexCurve( start, minX, minY, invSize ) { - - let p = start; - do { - - if ( p.z === null ) p.z = zOrder( p.x, p.y, minX, minY, invSize ); - p.prevZ = p.prev; - p.nextZ = p.next; - p = p.next; - - } while ( p !== start ); - - p.prevZ.nextZ = null; - p.prevZ = null; - - sortLinked( p ); - - } - - // Simon Tatham's linked list merge sort algorithm - // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html - function sortLinked( list ) { - - let i, p, q, e, tail, numMerges, pSize, qSize, - inSize = 1; - - do { - - p = list; - list = null; - tail = null; - numMerges = 0; - - while ( p ) { - - numMerges ++; - q = p; - pSize = 0; - for ( i = 0; i < inSize; i ++ ) { - - pSize ++; - q = q.nextZ; - if ( ! q ) break; - - } - - qSize = inSize; - - while ( pSize > 0 || ( qSize > 0 && q ) ) { - - if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { - - e = p; - p = p.nextZ; - pSize --; - - } else { - - e = q; - q = q.nextZ; - qSize --; - - } - - if ( tail ) tail.nextZ = e; - else list = e; - - e.prevZ = tail; - tail = e; - - } - - p = q; - - } - - tail.nextZ = null; - inSize *= 2; - - } while ( numMerges > 1 ); - - return list; - - } - - // z-order of a point given coords and inverse of the longer side of data bbox - function zOrder( x, y, minX, minY, invSize ) { - - // coords are transformed into non-negative 15-bit integer range - x = 32767 * ( x - minX ) * invSize; - y = 32767 * ( y - minY ) * invSize; - - x = ( x | ( x << 8 ) ) & 0x00FF00FF; - x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; - x = ( x | ( x << 2 ) ) & 0x33333333; - x = ( x | ( x << 1 ) ) & 0x55555555; - - y = ( y | ( y << 8 ) ) & 0x00FF00FF; - y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; - y = ( y | ( y << 2 ) ) & 0x33333333; - y = ( y | ( y << 1 ) ) & 0x55555555; - - return x | ( y << 1 ); - - } - - // find the leftmost node of a polygon ring - function getLeftmost( start ) { - - let p = start, - leftmost = start; - do { - - if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p; - p = p.next; - - } while ( p !== start ); - - return leftmost; - - } - - // check if a point lies within a convex triangle - function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { - - return ( cx - px ) * ( ay - py ) - ( ax - px ) * ( cy - py ) >= 0 && - ( ax - px ) * ( by - py ) - ( bx - px ) * ( ay - py ) >= 0 && - ( bx - px ) * ( cy - py ) - ( cx - px ) * ( by - py ) >= 0; - - } - - // check if a diagonal between two polygon nodes is valid (lies in polygon interior) - function isValidDiagonal( a, b ) { - - return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges - ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible - ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors - equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case - - } - - // signed area of a triangle - function area( p, q, r ) { - - return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); - - } - - // check if two points are equal - function equals( p1, p2 ) { - - return p1.x === p2.x && p1.y === p2.y; - - } - - // check if two segments intersect - function intersects( p1, q1, p2, q2 ) { - - const o1 = sign( area( p1, q1, p2 ) ); - const o2 = sign( area( p1, q1, q2 ) ); - const o3 = sign( area( p2, q2, p1 ) ); - const o4 = sign( area( p2, q2, q1 ) ); - - if ( o1 !== o2 && o3 !== o4 ) return true; // general case - - if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 - if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 - if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 - if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 - - return false; - - } - - // for collinear points p, q, r, check if point q lies on segment pr - function onSegment( p, q, r ) { - - return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y ); - - } - - function sign( num ) { - - return num > 0 ? 1 : num < 0 ? - 1 : 0; - - } - - // check if a polygon diagonal intersects any polygon segments - function intersectsPolygon( a, b ) { - - let p = a; - do { - - if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && - intersects( p, p.next, a, b ) ) return true; - p = p.next; - - } while ( p !== a ); - - return false; - - } - - // check if a polygon diagonal is locally inside the polygon - function locallyInside( a, b ) { - - return area( a.prev, a, a.next ) < 0 ? - area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 : - area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0; - - } - - // check if the middle point of a polygon diagonal is inside the polygon - function middleInside( a, b ) { - - let p = a, - inside = false; - const px = ( a.x + b.x ) / 2, - py = ( a.y + b.y ) / 2; - do { - - if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y && - ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) ) - inside = ! inside; - p = p.next; - - } while ( p !== a ); - - return inside; - - } - - // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; - // if one belongs to the outer ring and another to a hole, it merges it into a single ring - function splitPolygon( a, b ) { - - const a2 = new Node( a.i, a.x, a.y ), - b2 = new Node( b.i, b.x, b.y ), - an = a.next, - bp = b.prev; - - a.next = b; - b.prev = a; - - a2.next = an; - an.prev = a2; - - b2.next = a2; - a2.prev = b2; - - bp.next = b2; - b2.prev = bp; - - return b2; - - } - - // create a node and optionally link it with previous one (in a circular doubly linked list) - function insertNode( i, x, y, last ) { - - const p = new Node( i, x, y ); - - if ( ! last ) { - - p.prev = p; - p.next = p; - - } else { - - p.next = last.next; - p.prev = last; - last.next.prev = p; - last.next = p; - - } - - return p; - - } - - function removeNode( p ) { - - p.next.prev = p.prev; - p.prev.next = p.next; - - if ( p.prevZ ) p.prevZ.nextZ = p.nextZ; - if ( p.nextZ ) p.nextZ.prevZ = p.prevZ; - - } - - function Node( i, x, y ) { - - // vertex index in coordinates array - this.i = i; - - // vertex coordinates - this.x = x; - this.y = y; - - // previous and next vertex nodes in a polygon ring - this.prev = null; - this.next = null; - - // z-order curve value - this.z = null; - - // previous and next nodes in z-order - this.prevZ = null; - this.nextZ = null; - - // indicates whether this is a steiner point - this.steiner = false; - - } - - function signedArea( data, start, end, dim ) { - - let sum = 0; - for ( let i = start, j = end - dim; i < end; i += dim ) { - - sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); - j = i; - - } - - return sum; - - } - - class ShapeUtils { - - // calculate area of the contour polygon - - static area( contour ) { - - const n = contour.length; - let a = 0.0; - - for ( let p = n - 1, q = 0; q < n; p = q ++ ) { - - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - - } - - return a * 0.5; - - } - - static isClockWise( pts ) { - - return ShapeUtils.area( pts ) < 0; - - } - - static triangulateShape( contour, holes ) { - - const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] - const holeIndices = []; // array of hole indices - const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] - - removeDupEndPts( contour ); - addContour( vertices, contour ); - - // - - let holeIndex = contour.length; - - holes.forEach( removeDupEndPts ); - - for ( let i = 0; i < holes.length; i ++ ) { - - holeIndices.push( holeIndex ); - holeIndex += holes[ i ].length; - addContour( vertices, holes[ i ] ); - - } - - // - - const triangles = Earcut.triangulate( vertices, holeIndices ); - - // - - for ( let i = 0; i < triangles.length; i += 3 ) { - - faces.push( triangles.slice( i, i + 3 ) ); - - } - - return faces; - - } - - } - - function removeDupEndPts( points ) { - - const l = points.length; - - if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { - - points.pop(); - - } - - } - - function addContour( vertices, contour ) { - - for ( let i = 0; i < contour.length; i ++ ) { - - vertices.push( contour[ i ].x ); - vertices.push( contour[ i ].y ); - - } - - } - - /** - * Creates extruded geometry from a path shape. - * - * parameters = { - * - * curveSegments: , // number of points on the curves - * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too - * depth: , // Depth to extrude the shape - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into the original shape bevel goes - * bevelSize: , // how far from shape outline (including bevelOffset) is bevel - * bevelOffset: , // how far from shape outline does bevel start - * bevelSegments: , // number of bevel layers - * - * extrudePath: // curve to extrude shape along - * - * UVGenerator: // object that provides UV generator functions - * - * } - */ - - class ExtrudeGeometry extends BufferGeometry { - - constructor( shapes, options ) { - - super(); - - this.type = 'ExtrudeGeometry'; - - this.parameters = { - shapes: shapes, - options: options - }; - - shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; - - const scope = this; - - const verticesArray = []; - const uvArray = []; - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - addShape( shape ); - - } - - // build geometry - - this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); - - this.computeVertexNormals(); - - // functions - - function addShape( shape ) { - - const placeholder = []; - - // options - - const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - const steps = options.steps !== undefined ? options.steps : 1; - let depth = options.depth !== undefined ? options.depth : 100; - - let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; - let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; - let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; - let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; - let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; - - const extrudePath = options.extrudePath; - - const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; - - // deprecated options - - if ( options.amount !== undefined ) { - - console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' ); - depth = options.amount; - - } - - // - - let extrudePts, extrudeByPath = false; - let splineTube, binormal, normal, position2; - - if ( extrudePath ) { - - extrudePts = extrudePath.getSpacedPoints( steps ); - - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion - - // SETUP TNB variables - - // TODO1 - have a .isClosed in spline? - - splineTube = extrudePath.computeFrenetFrames( steps, false ); - - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - - binormal = new Vector3(); - normal = new Vector3(); - position2 = new Vector3(); - - } - - // Safeguards if bevels are not enabled - - if ( ! bevelEnabled ) { - - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; - bevelOffset = 0; - - } - - // Variables initialization - - const shapePoints = shape.extractPoints( curveSegments ); - - let vertices = shapePoints.shape; - const holes = shapePoints.holes; - - const reverse = ! ShapeUtils.isClockWise( vertices ); - - if ( reverse ) { - - vertices = vertices.reverse(); - - // Maybe we should also check if holes are in the opposite direction, just to be safe ... - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - if ( ShapeUtils.isClockWise( ahole ) ) { - - holes[ h ] = ahole.reverse(); - - } - - } - - } - - - const faces = ShapeUtils.triangulateShape( vertices, holes ); - - /* Vertices */ - - const contour = vertices; // vertices has all points but contour has only points of circumference - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - vertices = vertices.concat( ahole ); - - } - - - function scalePt2( pt, vec, size ) { - - if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); - - return vec.clone().multiplyScalar( size ).add( pt ); - - } - - const vlen = vertices.length, flen = faces.length; - - - // Find directions for point movement - - - function getBevelVec( inPt, inPrev, inNext ) { - - // computes for inPt the corresponding point inPt' on a new contour - // shifted by 1 unit (length of normalized vector) to the left - // if we walk along contour clockwise, this new contour is outside the old one - // - // inPt' is the intersection of the two lines parallel to the two - // adjacent edges of inPt at a distance of 1 unit on the left side. - - let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt - - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html - - const v_prev_x = inPt.x - inPrev.x, - v_prev_y = inPt.y - inPrev.y; - const v_next_x = inNext.x - inPt.x, - v_next_y = inNext.y - inPt.y; - - const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); - - // check for collinear edges - const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - if ( Math.abs( collinear0 ) > Number.EPSILON ) { - - // not collinear - - // length of vectors for normalizing - - const v_prev_len = Math.sqrt( v_prev_lensq ); - const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); - - // shift adjacent points by unit vectors to the left - - const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); - - const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); - - // scaling factor for v_prev to intersection point - - const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / - ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - - // vector from inPt to intersection point - - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - - // Don't normalize!, otherwise sharp corners become ugly - // but prevent crazy spikes - const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); - if ( v_trans_lensq <= 2 ) { - - return new Vector2( v_trans_x, v_trans_y ); - - } else { - - shrink_by = Math.sqrt( v_trans_lensq / 2 ); - - } - - } else { - - // handle special case of collinear edges - - let direction_eq = false; // assumes: opposite - - if ( v_prev_x > Number.EPSILON ) { - - if ( v_next_x > Number.EPSILON ) { - - direction_eq = true; - - } - - } else { - - if ( v_prev_x < - Number.EPSILON ) { - - if ( v_next_x < - Number.EPSILON ) { - - direction_eq = true; - - } - - } else { - - if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { - - direction_eq = true; - - } - - } - - } - - if ( direction_eq ) { - - // console.log("Warning: lines are a straight sequence"); - v_trans_x = - v_prev_y; - v_trans_y = v_prev_x; - shrink_by = Math.sqrt( v_prev_lensq ); - - } else { - - // console.log("Warning: lines are a straight spike"); - v_trans_x = v_prev_x; - v_trans_y = v_prev_y; - shrink_by = Math.sqrt( v_prev_lensq / 2 ); - - } - - } - - return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - - } - - - const contourMovements = []; - - for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) - - contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - - } - - const holesMovements = []; - let oneHoleMovements, verticesMovements = contourMovements.concat(); - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - - oneHoleMovements = []; - - for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - - if ( j === il ) j = 0; - if ( k === il ) k = 0; - - // (j)---(i)---(k) - oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); - - } - - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); - - } - - - // Loop bevelSegments, 1 for the front, 1 for the back - - for ( let b = 0; b < bevelSegments; b ++ ) { - - //for ( b = bevelSegments; b > 0; b -- ) { - - const t = b / bevelSegments; - const z = bevelThickness * Math.cos( t * Math.PI / 2 ); - const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - - // contract shape - - for ( let i = 0, il = contour.length; i < il; i ++ ) { - - const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - - v( vert.x, vert.y, - z ); - - } - - // expand holes - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( let i = 0, il = ahole.length; i < il; i ++ ) { - - const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - v( vert.x, vert.y, - z ); - - } - - } - - } - - const bs = bevelSize + bevelOffset; - - // Back facing vertices - - for ( let i = 0; i < vlen; i ++ ) { - - const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, 0 ); - - } else { - - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - - normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - // Add stepped vertices... - // Including front facing vertices - - for ( let s = 1; s <= steps; s ++ ) { - - for ( let i = 0; i < vlen; i ++ ) { - - const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, depth / steps * s ); - - } else { - - // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - - normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); - - position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); - - v( position2.x, position2.y, position2.z ); - - } - - } - - } - - - // Add bevel segments planes - - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( let b = bevelSegments - 1; b >= 0; b -- ) { - - const t = b / bevelSegments; - const z = bevelThickness * Math.cos( t * Math.PI / 2 ); - const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - - // contract shape - - for ( let i = 0, il = contour.length; i < il; i ++ ) { - - const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, depth + z ); - - } - - // expand holes - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; - - for ( let i = 0, il = ahole.length; i < il; i ++ ) { - - const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); - - if ( ! extrudeByPath ) { - - v( vert.x, vert.y, depth + z ); - - } else { - - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); - - } - - } - - } - - } - - /* Faces */ - - // Top and bottom faces - - buildLidFaces(); - - // Sides faces - - buildSideFaces(); - - - ///// Internal functions - - function buildLidFaces() { - - const start = verticesArray.length / 3; - - if ( bevelEnabled ) { - - let layer = 0; // steps + 1 - let offset = vlen * layer; - - // Bottom faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); - - } - - layer = steps + bevelSegments * 2; - offset = vlen * layer; - - // Top faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); - - } - - } else { - - // Bottom faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ] ); - - } - - // Top faces - - for ( let i = 0; i < flen; i ++ ) { - - const face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); - - } - - } - - scope.addGroup( start, verticesArray.length / 3 - start, 0 ); - - } - - // Create faces for the z-sides of the shape - - function buildSideFaces() { - - const start = verticesArray.length / 3; - let layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; - - for ( let h = 0, hl = holes.length; h < hl; h ++ ) { - - const ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); - - //, true - layeroffset += ahole.length; - - } - - - scope.addGroup( start, verticesArray.length / 3 - start, 1 ); - - - } - - function sidewalls( contour, layeroffset ) { - - let i = contour.length; - - while ( -- i >= 0 ) { - - const j = i; - let k = i - 1; - if ( k < 0 ) k = contour.length - 1; - - //console.log('b', i,j, i-1, k,vertices.length); - - for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { - - const slen1 = vlen * s; - const slen2 = vlen * ( s + 1 ); - - const a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; - - f4( a, b, c, d ); - - } - - } - - } - - function v( x, y, z ) { - - placeholder.push( x ); - placeholder.push( y ); - placeholder.push( z ); - - } - - - function f3( a, b, c ) { - - addVertex( a ); - addVertex( b ); - addVertex( c ); - - const nextIndex = verticesArray.length / 3; - const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - - } - - function f4( a, b, c, d ) { - - addVertex( a ); - addVertex( b ); - addVertex( d ); - - addVertex( b ); - addVertex( c ); - addVertex( d ); - - - const nextIndex = verticesArray.length / 3; - const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 3 ] ); - - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - addUV( uvs[ 3 ] ); - - } - - function addVertex( index ) { - - verticesArray.push( placeholder[ index * 3 + 0 ] ); - verticesArray.push( placeholder[ index * 3 + 1 ] ); - verticesArray.push( placeholder[ index * 3 + 2 ] ); - - } - - - function addUV( vector2 ) { - - uvArray.push( vector2.x ); - uvArray.push( vector2.y ); - - } - - } - - } - - toJSON() { - - const data = super.toJSON(); - - const shapes = this.parameters.shapes; - const options = this.parameters.options; - - return toJSON$1( shapes, options, data ); - - } - - static fromJSON( data, shapes ) { - - const geometryShapes = []; - - for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { - - const shape = shapes[ data.shapes[ j ] ]; - - geometryShapes.push( shape ); - - } - - const extrudePath = data.options.extrudePath; - - if ( extrudePath !== undefined ) { - - data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); - - } - - return new ExtrudeGeometry( geometryShapes, data.options ); - - } - - } - - const WorldUVGenerator = { - - generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { - - const a_x = vertices[ indexA * 3 ]; - const a_y = vertices[ indexA * 3 + 1 ]; - const b_x = vertices[ indexB * 3 ]; - const b_y = vertices[ indexB * 3 + 1 ]; - const c_x = vertices[ indexC * 3 ]; - const c_y = vertices[ indexC * 3 + 1 ]; - - return [ - new Vector2( a_x, a_y ), - new Vector2( b_x, b_y ), - new Vector2( c_x, c_y ) - ]; - - }, - - generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { - - const a_x = vertices[ indexA * 3 ]; - const a_y = vertices[ indexA * 3 + 1 ]; - const a_z = vertices[ indexA * 3 + 2 ]; - const b_x = vertices[ indexB * 3 ]; - const b_y = vertices[ indexB * 3 + 1 ]; - const b_z = vertices[ indexB * 3 + 2 ]; - const c_x = vertices[ indexC * 3 ]; - const c_y = vertices[ indexC * 3 + 1 ]; - const c_z = vertices[ indexC * 3 + 2 ]; - const d_x = vertices[ indexD * 3 ]; - const d_y = vertices[ indexD * 3 + 1 ]; - const d_z = vertices[ indexD * 3 + 2 ]; - - if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { - - return [ - new Vector2( a_x, 1 - a_z ), - new Vector2( b_x, 1 - b_z ), - new Vector2( c_x, 1 - c_z ), - new Vector2( d_x, 1 - d_z ) - ]; - - } else { - - return [ - new Vector2( a_y, 1 - a_z ), - new Vector2( b_y, 1 - b_z ), - new Vector2( c_y, 1 - c_z ), - new Vector2( d_y, 1 - d_z ) - ]; - - } - - } - - }; - - function toJSON$1( shapes, options, data ) { - - data.shapes = []; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - data.shapes.push( shape.uuid ); - - } - - } else { - - data.shapes.push( shapes.uuid ); - - } - - if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); - - return data; - - } - - class IcosahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const t = ( 1 + Math.sqrt( 5 ) ) / 2; - - const vertices = [ - - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, - 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, - t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 - ]; - - const indices = [ - 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 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'IcosahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new IcosahedronGeometry( data.radius, data.detail ); - - } - - } - - class LatheGeometry extends BufferGeometry { - - constructor( points, segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) { - - super(); - - this.type = 'LatheGeometry'; - - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; - - segments = Math.floor( segments ); - - // clamp phiLength so it's in range of [ 0, 2PI ] - - phiLength = clamp( phiLength, 0, Math.PI * 2 ); - - // buffers - - const indices = []; - const vertices = []; - const uvs = []; - - // helper variables - - const inverseSegments = 1.0 / segments; - const vertex = new Vector3(); - const uv = new Vector2(); - - // generate vertices and uvs - - for ( let i = 0; i <= segments; i ++ ) { - - const phi = phiStart + i * inverseSegments * phiLength; - - const sin = Math.sin( phi ); - const cos = Math.cos( phi ); - - for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { - - // vertex - - vertex.x = points[ j ].x * sin; - vertex.y = points[ j ].y; - vertex.z = points[ j ].x * cos; - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // uv - - uv.x = i / segments; - uv.y = j / ( points.length - 1 ); - - uvs.push( uv.x, uv.y ); - - - } - - } - - // indices - - for ( let i = 0; i < segments; i ++ ) { - - for ( let j = 0; j < ( points.length - 1 ); j ++ ) { - - const base = j + i * points.length; - - const a = base; - const b = base + points.length; - const c = base + points.length + 1; - const d = base + 1; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // generate normals - - this.computeVertexNormals(); - - // if the geometry is closed, we need to average the normals along the seam. - // because the corresponding vertices are identical (but still have different UVs). - - if ( phiLength === Math.PI * 2 ) { - - const normals = this.attributes.normal.array; - const n1 = new Vector3(); - const n2 = new Vector3(); - const n = new Vector3(); - - // this is the buffer offset for the last line of vertices - - const base = segments * points.length * 3; - - for ( let i = 0, j = 0; i < points.length; i ++, j += 3 ) { - - // select the normal of the vertex in the first line - - n1.x = normals[ j + 0 ]; - n1.y = normals[ j + 1 ]; - n1.z = normals[ j + 2 ]; - - // select the normal of the vertex in the last line - - n2.x = normals[ base + j + 0 ]; - n2.y = normals[ base + j + 1 ]; - n2.z = normals[ base + j + 2 ]; - - // average normals - - n.addVectors( n1, n2 ).normalize(); - - // assign the new values to both normals - - normals[ j + 0 ] = normals[ base + j + 0 ] = n.x; - normals[ j + 1 ] = normals[ base + j + 1 ] = n.y; - normals[ j + 2 ] = normals[ base + j + 2 ] = n.z; - - } - - } - - } - - static fromJSON( data ) { - - return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength ); - - } - - } - - class OctahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const vertices = [ - 1, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, - 1, 0, 0, 0, 1, 0, 0, - 1 - ]; - - const indices = [ - 0, 2, 4, 0, 4, 3, 0, 3, 5, - 0, 5, 2, 1, 2, 5, 1, 5, 3, - 1, 3, 4, 1, 4, 2 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'OctahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new OctahedronGeometry( data.radius, data.detail ); - - } - - } - - /** - * Parametric Surfaces Geometry - * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html - */ - - class ParametricGeometry extends BufferGeometry { - - constructor( func, slices, stacks ) { - - super(); - - this.type = 'ParametricGeometry'; - - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - const EPS = 0.00001; - - const normal = new Vector3(); - - const p0 = new Vector3(), p1 = new Vector3(); - const pu = new Vector3(), pv = new Vector3(); - - if ( func.length < 3 ) { - - console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' ); - - } - - // generate vertices, normals and uvs - - const sliceCount = slices + 1; - - for ( let i = 0; i <= stacks; i ++ ) { - - const v = i / stacks; - - for ( let j = 0; j <= slices; j ++ ) { - - const u = j / slices; - - // vertex - - func( u, v, p0 ); - vertices.push( p0.x, p0.y, p0.z ); - - // normal - - // approximate tangent vectors via finite differences - - if ( u - EPS >= 0 ) { - - func( u - EPS, v, p1 ); - pu.subVectors( p0, p1 ); - - } else { - - func( u + EPS, v, p1 ); - pu.subVectors( p1, p0 ); - - } - - if ( v - EPS >= 0 ) { - - func( u, v - EPS, p1 ); - pv.subVectors( p0, p1 ); - - } else { - - func( u, v + EPS, p1 ); - pv.subVectors( p1, p0 ); - - } - - // cross product of tangent vectors returns surface normal - - normal.crossVectors( pu, pv ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u, v ); - - } - - } - - // generate indices - - for ( let i = 0; i < stacks; i ++ ) { - - for ( let j = 0; j < slices; j ++ ) { - - const a = i * sliceCount + j; - const b = i * sliceCount + j + 1; - const c = ( i + 1 ) * sliceCount + j + 1; - const d = ( i + 1 ) * sliceCount + j; - - // faces one and two - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - } - - class RingGeometry extends BufferGeometry { - - constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 8, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) { - - super(); - - this.type = 'RingGeometry'; - - this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - thetaSegments = Math.max( 3, thetaSegments ); - phiSegments = Math.max( 1, phiSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // some helper variables - - let radius = innerRadius; - const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); - const vertex = new Vector3(); - const uv = new Vector2(); - - // generate vertices, normals and uvs - - for ( let j = 0; j <= phiSegments; j ++ ) { - - for ( let i = 0; i <= thetaSegments; i ++ ) { - - // values are generate from the inside of the ring to the outside - - const segment = thetaStart + i / thetaSegments * thetaLength; - - // vertex - - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normals.push( 0, 0, 1 ); - - // uv - - uv.x = ( vertex.x / outerRadius + 1 ) / 2; - uv.y = ( vertex.y / outerRadius + 1 ) / 2; - - uvs.push( uv.x, uv.y ); - - } - - // increase the radius for next row of vertices - - radius += radiusStep; - - } - - // indices - - for ( let j = 0; j < phiSegments; j ++ ) { - - const thetaSegmentLevel = j * ( thetaSegments + 1 ); - - for ( let i = 0; i < thetaSegments; i ++ ) { - - const segment = i + thetaSegmentLevel; - - const a = segment; - const b = segment + thetaSegments + 1; - const c = segment + thetaSegments + 2; - const d = segment + 1; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - static fromJSON( data ) { - - return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); - - } - - } - - class ShapeGeometry extends BufferGeometry { - - constructor( shapes, curveSegments = 12 ) { - - super(); - this.type = 'ShapeGeometry'; - - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - let groupStart = 0; - let groupCount = 0; - - // allow single and array values for "shapes" parameter - - if ( Array.isArray( shapes ) === false ) { - - addShape( shapes ); - - } else { - - for ( let i = 0; i < shapes.length; i ++ ) { - - addShape( shapes[ i ] ); - - this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support - - groupStart += groupCount; - groupCount = 0; - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - - // helper functions - - function addShape( shape ) { - - const indexOffset = vertices.length / 3; - const points = shape.extractPoints( curveSegments ); - - let shapeVertices = points.shape; - const shapeHoles = points.holes; - - // check direction of vertices - - if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { - - shapeVertices = shapeVertices.reverse(); - - } - - for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { - - const shapeHole = shapeHoles[ i ]; - - if ( ShapeUtils.isClockWise( shapeHole ) === true ) { - - shapeHoles[ i ] = shapeHole.reverse(); - - } - - } - - const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); - - // join vertices of inner and outer paths to a single array - - for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { - - const shapeHole = shapeHoles[ i ]; - shapeVertices = shapeVertices.concat( shapeHole ); - - } - - // vertices, normals, uvs - - for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) { - - const vertex = shapeVertices[ i ]; - - vertices.push( vertex.x, vertex.y, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( vertex.x, vertex.y ); // world uvs - - } - - // incides - - for ( let i = 0, l = faces.length; i < l; i ++ ) { - - const face = faces[ i ]; - - const a = face[ 0 ] + indexOffset; - const b = face[ 1 ] + indexOffset; - const c = face[ 2 ] + indexOffset; - - indices.push( a, b, c ); - groupCount += 3; - - } - - } - - } - - toJSON() { - - const data = super.toJSON(); - - const shapes = this.parameters.shapes; - - return toJSON( shapes, data ); - - } - - static fromJSON( data, shapes ) { - - const geometryShapes = []; - - for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { - - const shape = shapes[ data.shapes[ j ] ]; - - geometryShapes.push( shape ); - - } - - return new ShapeGeometry( geometryShapes, data.curveSegments ); - - } - - } - - function toJSON( shapes, data ) { - - data.shapes = []; - - if ( Array.isArray( shapes ) ) { - - for ( let i = 0, l = shapes.length; i < l; i ++ ) { - - const shape = shapes[ i ]; - - data.shapes.push( shape.uuid ); - - } - - } else { - - data.shapes.push( shapes.uuid ); - - } - - return data; - - } - - class SphereGeometry extends BufferGeometry { - - constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { - - super(); - this.type = 'SphereGeometry'; - - this.parameters = { - radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength - }; - - widthSegments = Math.max( 3, Math.floor( widthSegments ) ); - heightSegments = Math.max( 2, Math.floor( heightSegments ) ); - - const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); - - let index = 0; - const grid = []; - - const vertex = new Vector3(); - const normal = new Vector3(); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // generate vertices, normals and uvs - - for ( let iy = 0; iy <= heightSegments; iy ++ ) { - - const verticesRow = []; - - const v = iy / heightSegments; - - // special case for the poles - - let uOffset = 0; - - if ( iy == 0 && thetaStart == 0 ) { - - uOffset = 0.5 / widthSegments; - - } else if ( iy == heightSegments && thetaEnd == Math.PI ) { - - uOffset = - 0.5 / widthSegments; - - } - - for ( let ix = 0; ix <= widthSegments; ix ++ ) { - - const u = ix / widthSegments; - - // vertex - - vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); - vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - normal.copy( vertex ).normalize(); - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( u + uOffset, 1 - v ); - - verticesRow.push( index ++ ); - - } - - grid.push( verticesRow ); - - } - - // indices - - for ( let iy = 0; iy < heightSegments; iy ++ ) { - - for ( let ix = 0; ix < widthSegments; ix ++ ) { - - const a = grid[ iy ][ ix + 1 ]; - const b = grid[ iy ][ ix ]; - const c = grid[ iy + 1 ][ ix ]; - const d = grid[ iy + 1 ][ ix + 1 ]; - - if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); - if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - static fromJSON( data ) { - - return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); - - } - - } - - class TetrahedronGeometry extends PolyhedronGeometry { - - constructor( radius = 1, detail = 0 ) { - - const vertices = [ - 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 - ]; - - const indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; - - super( vertices, indices, radius, detail ); - - this.type = 'TetrahedronGeometry'; - - this.parameters = { - radius: radius, - detail: detail - }; - - } - - static fromJSON( data ) { - - return new TetrahedronGeometry( data.radius, data.detail ); - - } - - } - - /** - * Text = 3D Text - * - * parameters = { - * font: , // font - * - * size: , // size of the text - * height: , // thickness to extrude text - * curveSegments: , // number of points on the curves - * - * bevelEnabled: , // turn on bevel - * bevelThickness: , // how deep into text bevel goes - * bevelSize: , // how far from text outline (including bevelOffset) is bevel - * bevelOffset: // how far from text outline does bevel start - * } - */ - - class TextGeometry extends ExtrudeGeometry { - - constructor( text, parameters = {} ) { - - const font = parameters.font; - - if ( ! ( font && font.isFont ) ) { - - console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' ); - return new BufferGeometry(); - - } - - const shapes = font.generateShapes( text, parameters.size ); - - // translate parameters to ExtrudeGeometry API - - parameters.depth = parameters.height !== undefined ? parameters.height : 50; - - // defaults - - if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; - if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; - if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; - - super( shapes, parameters ); - - this.type = 'TextGeometry'; - - } - - } - - class TorusGeometry extends BufferGeometry { - - constructor( radius = 1, tube = 0.4, radialSegments = 8, tubularSegments = 6, arc = Math.PI * 2 ) { - - super(); - this.type = 'TorusGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; - - radialSegments = Math.floor( radialSegments ); - tubularSegments = Math.floor( tubularSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const center = new Vector3(); - const vertex = new Vector3(); - const normal = new Vector3(); - - // generate vertices, normals and uvs - - for ( let j = 0; j <= radialSegments; j ++ ) { - - for ( let i = 0; i <= tubularSegments; i ++ ) { - - const u = i / tubularSegments * arc; - const v = j / radialSegments * Math.PI * 2; - - // vertex - - vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); - vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); - vertex.z = tube * Math.sin( v ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal - - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); - normal.subVectors( vertex, center ).normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); - - } - - } - - // generate indices - - for ( let j = 1; j <= radialSegments; j ++ ) { - - for ( let i = 1; i <= tubularSegments; i ++ ) { - - // indices - - const a = ( tubularSegments + 1 ) * j + i - 1; - const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; - const c = ( tubularSegments + 1 ) * ( j - 1 ) + i; - const d = ( tubularSegments + 1 ) * j + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - static fromJSON( data ) { - - return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); - - } - - } - - class TorusKnotGeometry extends BufferGeometry { - - constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) { - - super(); - this.type = 'TorusKnotGeometry'; - - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; - - tubularSegments = Math.floor( tubularSegments ); - radialSegments = Math.floor( radialSegments ); - - // buffers - - const indices = []; - const vertices = []; - const normals = []; - const uvs = []; - - // helper variables - - const vertex = new Vector3(); - const normal = new Vector3(); - - const P1 = new Vector3(); - const P2 = new Vector3(); - - const B = new Vector3(); - const T = new Vector3(); - const N = new Vector3(); - - // generate vertices, normals and uvs - - for ( let i = 0; i <= tubularSegments; ++ i ) { - - // the radian "u" is used to calculate the position on the torus curve of the current tubular segement - - const u = i / tubularSegments * p * Math.PI * 2; - - // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. - // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions - - calculatePositionOnCurve( u, p, q, radius, P1 ); - calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); - - // calculate orthonormal basis - - T.subVectors( P2, P1 ); - N.addVectors( P2, P1 ); - B.crossVectors( T, N ); - N.crossVectors( B, T ); - - // normalize B, N. T can be ignored, we don't use it - - B.normalize(); - N.normalize(); - - for ( let j = 0; j <= radialSegments; ++ j ) { - - // now calculate the vertices. they are nothing more than an extrusion of the torus curve. - // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. - - const v = j / radialSegments * Math.PI * 2; - const cx = - tube * Math.cos( v ); - const cy = tube * Math.sin( v ); - - // now calculate the final vertex position. - // first we orient the extrusion with our basis vectos, then we add it to the current position on the curve - - vertex.x = P1.x + ( cx * N.x + cy * B.x ); - vertex.y = P1.y + ( cx * N.y + cy * B.y ); - vertex.z = P1.z + ( cx * N.z + cy * B.z ); - - vertices.push( vertex.x, vertex.y, vertex.z ); - - // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) - - normal.subVectors( vertex, P1 ).normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // uv - - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); - - } - - } - - // generate indices - - for ( let j = 1; j <= tubularSegments; j ++ ) { - - for ( let i = 1; i <= radialSegments; i ++ ) { - - // indices - - const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - const b = ( radialSegments + 1 ) * j + ( i - 1 ); - const c = ( radialSegments + 1 ) * j + i; - const d = ( radialSegments + 1 ) * ( j - 1 ) + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // this function calculates the current position on the torus curve - - function calculatePositionOnCurve( u, p, q, radius, position ) { - - const cu = Math.cos( u ); - const su = Math.sin( u ); - const quOverP = q / p * u; - const cs = Math.cos( quOverP ); - - position.x = radius * ( 2 + cs ) * 0.5 * cu; - position.y = radius * ( 2 + cs ) * su * 0.5; - position.z = radius * Math.sin( quOverP ) * 0.5; - - } - - } - - static fromJSON( data ) { - - return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q ); - - } - - } - - class TubeGeometry extends BufferGeometry { - - constructor( path, tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) { - - super(); - this.type = 'TubeGeometry'; - - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; - - const frames = path.computeFrenetFrames( tubularSegments, closed ); - - // expose internals - - this.tangents = frames.tangents; - this.normals = frames.normals; - this.binormals = frames.binormals; - - // helper variables - - const vertex = new Vector3(); - const normal = new Vector3(); - const uv = new Vector2(); - let P = new Vector3(); - - // buffer - - const vertices = []; - const normals = []; - const uvs = []; - const indices = []; - - // create buffer data - - generateBufferData(); - - // build geometry - - this.setIndex( indices ); - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - // functions - - function generateBufferData() { - - for ( let i = 0; i < tubularSegments; i ++ ) { - - generateSegment( i ); - - } - - // if the geometry is not closed, generate the last row of vertices and normals - // at the regular position on the given path - // - // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) - - generateSegment( ( closed === false ) ? tubularSegments : 0 ); - - // uvs are generated in a separate function. - // this makes it easy compute correct values for closed geometries - - generateUVs(); - - // finally create faces - - generateIndices(); - - } - - function generateSegment( i ) { - - // we use getPointAt to sample evenly distributed points from the given path - - P = path.getPointAt( i / tubularSegments, P ); - - // retrieve corresponding normal and binormal - - const N = frames.normals[ i ]; - const B = frames.binormals[ i ]; - - // generate normals and vertices for the current segment - - for ( let j = 0; j <= radialSegments; j ++ ) { - - const v = j / radialSegments * Math.PI * 2; - - const sin = Math.sin( v ); - const cos = - Math.cos( v ); - - // normal - - normal.x = ( cos * N.x + sin * B.x ); - normal.y = ( cos * N.y + sin * B.y ); - normal.z = ( cos * N.z + sin * B.z ); - normal.normalize(); - - normals.push( normal.x, normal.y, normal.z ); - - // vertex - - vertex.x = P.x + radius * normal.x; - vertex.y = P.y + radius * normal.y; - vertex.z = P.z + radius * normal.z; - - vertices.push( vertex.x, vertex.y, vertex.z ); - - } - - } - - function generateIndices() { - - for ( let j = 1; j <= tubularSegments; j ++ ) { - - for ( let i = 1; i <= radialSegments; i ++ ) { - - const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - const b = ( radialSegments + 1 ) * j + ( i - 1 ); - const c = ( radialSegments + 1 ) * j + i; - const d = ( radialSegments + 1 ) * ( j - 1 ) + i; - - // faces - - indices.push( a, b, d ); - indices.push( b, c, d ); - - } - - } - - } - - function generateUVs() { - - for ( let i = 0; i <= tubularSegments; i ++ ) { - - for ( let j = 0; j <= radialSegments; j ++ ) { - - uv.x = i / tubularSegments; - uv.y = j / radialSegments; - - uvs.push( uv.x, uv.y ); - - } - - } - - } - - } - - toJSON() { - - const data = super.toJSON(); - - data.path = this.parameters.path.toJSON(); - - return data; - - } - - static fromJSON( data ) { - - // This only works for built-in curves (e.g. CatmullRomCurve3). - // User defined curves or instances of CurvePath will not be deserialized. - return new TubeGeometry( - new Curves[ data.path.type ]().fromJSON( data.path ), - data.tubularSegments, - data.radius, - data.radialSegments, - data.closed - ); - - } - - } - - class WireframeGeometry extends BufferGeometry { - - constructor( geometry ) { - - super(); - this.type = 'WireframeGeometry'; - - if ( geometry.isGeometry === true ) { - - console.error( 'THREE.WireframeGeometry no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - return; - - } - - // buffer - - const vertices = []; - const edges = new Set(); - - // helper variables - - const start = new Vector3(); - const end = new Vector3(); - - if ( geometry.index !== null ) { - - // indexed BufferGeometry - - const position = geometry.attributes.position; - const indices = geometry.index; - let groups = geometry.groups; - - if ( groups.length === 0 ) { - - groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; - - } - - // create a data structure that contains all eges without duplicates - - for ( let o = 0, ol = groups.length; o < ol; ++ o ) { - - const group = groups[ o ]; - - const groupStart = group.start; - const groupCount = group.count; - - for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { - - for ( let j = 0; j < 3; j ++ ) { - - const index1 = indices.getX( i + j ); - const index2 = indices.getX( i + ( j + 1 ) % 3 ); - - start.fromBufferAttribute( position, index1 ); - end.fromBufferAttribute( position, index2 ); - - if ( isUniqueEdge( start, end, edges ) === true ) { - - vertices.push( start.x, start.y, start.z ); - vertices.push( end.x, end.y, end.z ); - - } - - } - - } - - } - - } else { - - // non-indexed BufferGeometry - - const position = geometry.attributes.position; - - for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { - - for ( let j = 0; j < 3; j ++ ) { - - // three edges per triangle, an edge is represented as (index1, index2) - // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) - - const index1 = 3 * i + j; - const index2 = 3 * i + ( ( j + 1 ) % 3 ); - - start.fromBufferAttribute( position, index1 ); - end.fromBufferAttribute( position, index2 ); - - if ( isUniqueEdge( start, end, edges ) === true ) { - - vertices.push( start.x, start.y, start.z ); - vertices.push( end.x, end.y, end.z ); - - } - - } - - } - - } - - // build geometry - - this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - - } - - } - - function isUniqueEdge( start, end, edges ) { - - const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; - const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge - - if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { - - return false; - - } else { - - edges.add( hash1, hash2 ); - return true; - - } - - } - - var Geometries = /*#__PURE__*/Object.freeze({ - __proto__: null, - BoxGeometry: BoxGeometry, - BoxBufferGeometry: BoxGeometry, - CircleGeometry: CircleGeometry, - CircleBufferGeometry: CircleGeometry, - ConeGeometry: ConeGeometry, - ConeBufferGeometry: ConeGeometry, - CylinderGeometry: CylinderGeometry, - CylinderBufferGeometry: CylinderGeometry, - DodecahedronGeometry: DodecahedronGeometry, - DodecahedronBufferGeometry: DodecahedronGeometry, - EdgesGeometry: EdgesGeometry, - ExtrudeGeometry: ExtrudeGeometry, - ExtrudeBufferGeometry: ExtrudeGeometry, - IcosahedronGeometry: IcosahedronGeometry, - IcosahedronBufferGeometry: IcosahedronGeometry, - LatheGeometry: LatheGeometry, - LatheBufferGeometry: LatheGeometry, - OctahedronGeometry: OctahedronGeometry, - OctahedronBufferGeometry: OctahedronGeometry, - ParametricGeometry: ParametricGeometry, - ParametricBufferGeometry: ParametricGeometry, - PlaneGeometry: PlaneGeometry, - PlaneBufferGeometry: PlaneGeometry, - PolyhedronGeometry: PolyhedronGeometry, - PolyhedronBufferGeometry: PolyhedronGeometry, - RingGeometry: RingGeometry, - RingBufferGeometry: RingGeometry, - ShapeGeometry: ShapeGeometry, - ShapeBufferGeometry: ShapeGeometry, - SphereGeometry: SphereGeometry, - SphereBufferGeometry: SphereGeometry, - TetrahedronGeometry: TetrahedronGeometry, - TetrahedronBufferGeometry: TetrahedronGeometry, - TextGeometry: TextGeometry, - TextBufferGeometry: TextGeometry, - TorusGeometry: TorusGeometry, - TorusBufferGeometry: TorusGeometry, - TorusKnotGeometry: TorusKnotGeometry, - TorusKnotBufferGeometry: TorusKnotGeometry, - TubeGeometry: TubeGeometry, - TubeBufferGeometry: TubeGeometry, - WireframeGeometry: WireframeGeometry - }); - - /** - * parameters = { - * color: - * } - */ - - class ShadowMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'ShadowMaterial'; - - this.color = new Color( 0x000000 ); - this.transparent = true; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - return this; - - } - - } - - ShadowMaterial.prototype.isShadowMaterial = true; - - /** - * parameters = { - * color: , - * roughness: , - * metalness: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * emissive: , - * emissiveIntensity: - * emissiveMap: new THREE.Texture( ), - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalMapType: THREE.TangentSpaceNormalMap, - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * roughnessMap: new THREE.Texture( ), - * - * metalnessMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ), - * envMapIntensity: - * - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * flatShading: - * } - */ - - class MeshStandardMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.defines = { 'STANDARD': '' }; - - this.type = 'MeshStandardMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.roughness = 1.0; - this.metalness = 0.0; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.roughnessMap = null; - - this.metalnessMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.envMapIntensity = 1.0; - - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.flatShading = false; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.defines = { 'STANDARD': '' }; - - this.color.copy( source.color ); - this.roughness = source.roughness; - this.metalness = source.metalness; - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.roughnessMap = source.roughnessMap; - - this.metalnessMap = source.metalnessMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.envMapIntensity = source.envMapIntensity; - - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.flatShading = source.flatShading; - - return this; - - } - - } - - MeshStandardMaterial.prototype.isMeshStandardMaterial = true; - - /** - * parameters = { - * clearcoat: , - * clearcoatMap: new THREE.Texture( ), - * clearcoatRoughness: , - * clearcoatRoughnessMap: new THREE.Texture( ), - * clearcoatNormalScale: , - * clearcoatNormalMap: new THREE.Texture( ), - * - * ior: , - * reflectivity: , - * - * sheenTint: , - * - * transmission: , - * transmissionMap: new THREE.Texture( ), - * - * thickness: , - * thicknessMap: new THREE.Texture( ), - * attenuationDistance: , - * attenuationTint: , - * - * specularIntensity: , - * specularIntensityhMap: new THREE.Texture( ), - * specularTint: , - * specularTintMap: new THREE.Texture( ) - * } - */ - - class MeshPhysicalMaterial extends MeshStandardMaterial { - - constructor( parameters ) { - - super(); - - this.defines = { - - 'STANDARD': '', - 'PHYSICAL': '' - - }; - - this.type = 'MeshPhysicalMaterial'; - - this.clearcoatMap = null; - this.clearcoatRoughness = 0.0; - this.clearcoatRoughnessMap = null; - this.clearcoatNormalScale = new Vector2( 1, 1 ); - this.clearcoatNormalMap = null; - - this.ior = 1.5; - - Object.defineProperty( this, 'reflectivity', { - get: function () { - - return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) ); - - }, - set: function ( reflectivity ) { - - this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity ); - - } - } ); - - this.sheenTint = new Color( 0x000000 ); - - this.transmission = 0.0; - this.transmissionMap = null; - - this.thickness = 0.01; - this.thicknessMap = null; - this.attenuationDistance = 0.0; - this.attenuationTint = new Color( 1, 1, 1 ); - - this.specularIntensity = 1.0; - this.specularIntensityMap = null; - this.specularTint = new Color( 1, 1, 1 ); - this.specularTintMap = null; - - this._clearcoat = 0; - this._transmission = 0; - - - this.setValues( parameters ); - - } - - get clearcoat() { - - return this._clearcoat; - - } - - set clearcoat( value ) { - - if ( this._clearcoat > 0 !== value > 0 ) { - - this.version ++; - - } - - this._clearcoat = value; - - } - - get transmission() { - - return this._transmission; - - } - - set transmission( value ) { - - if ( this._transmission > 0 !== value > 0 ) { - - this.version ++; - - } - - this._transmission = value; - - } - - - copy( source ) { - - super.copy( source ); - - this.defines = { - - 'STANDARD': '', - 'PHYSICAL': '' - - }; - - this.clearcoat = source.clearcoat; - this.clearcoatMap = source.clearcoatMap; - this.clearcoatRoughness = source.clearcoatRoughness; - this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; - this.clearcoatNormalMap = source.clearcoatNormalMap; - this.clearcoatNormalScale.copy( source.clearcoatNormalScale ); - - this.ior = source.ior; - - this.sheenTint.copy( source.sheenTint ); - - this.transmission = source.transmission; - this.transmissionMap = source.transmissionMap; - - this.thickness = source.thickness; - this.thicknessMap = source.thicknessMap; - this.attenuationDistance = source.attenuationDistance; - this.attenuationTint.copy( source.attenuationTint ); - - this.specularIntensity = source.specularIntensity; - this.specularIntensityMap = source.specularIntensityMap; - this.specularTint.copy( source.specularTint ); - this.specularTintMap = source.specularTintMap; - - return this; - - } - - } - - MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true; - - /** - * parameters = { - * color: , - * specular: , - * shininess: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * emissive: , - * emissiveIntensity: - * emissiveMap: new THREE.Texture( ), - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalMapType: THREE.TangentSpaceNormalMap, - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * specularMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.MultiplyOperation, - * reflectivity: , - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * flatShading: - * } - */ - - class MeshPhongMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'MeshPhongMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - this.specular = new Color( 0x111111 ); - this.shininess = 30; - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.flatShading = false; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - this.specular.copy( source.specular ); - this.shininess = source.shininess; - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - this.flatShading = source.flatShading; - - return this; - - } - - } - - MeshPhongMaterial.prototype.isMeshPhongMaterial = true; - - /** - * parameters = { - * color: , - * - * map: new THREE.Texture( ), - * gradientMap: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * emissive: , - * emissiveIntensity: - * emissiveMap: new THREE.Texture( ), - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalMapType: THREE.TangentSpaceNormalMap, - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * alphaMap: new THREE.Texture( ), - * - * wireframe: , - * wireframeLinewidth: , - * - * } - */ - - class MeshToonMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.defines = { 'TOON': '' }; - - this.type = 'MeshToonMaterial'; - - this.color = new Color( 0xffffff ); - - this.map = null; - this.gradientMap = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.alphaMap = null; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - this.gradientMap = source.gradientMap; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.alphaMap = source.alphaMap; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - return this; - - } - - } - - MeshToonMaterial.prototype.isMeshToonMaterial = true; - - /** - * parameters = { - * opacity: , - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalMapType: THREE.TangentSpaceNormalMap, - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * wireframe: , - * wireframeLinewidth: - * - * flatShading: - * } - */ - - class MeshNormalMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'MeshNormalMaterial'; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.wireframe = false; - this.wireframeLinewidth = 1; - - this.fog = false; - - this.flatShading = false; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - - this.flatShading = source.flatShading; - - return this; - - } - - } - - MeshNormalMaterial.prototype.isMeshNormalMaterial = true; - - /** - * parameters = { - * color: , - * opacity: , - * - * map: new THREE.Texture( ), - * - * lightMap: new THREE.Texture( ), - * lightMapIntensity: - * - * aoMap: new THREE.Texture( ), - * aoMapIntensity: - * - * emissive: , - * emissiveIntensity: - * emissiveMap: new THREE.Texture( ), - * - * specularMap: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ), - * combine: THREE.Multiply, - * reflectivity: , - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * } - */ - - class MeshLambertMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.type = 'MeshLambertMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - - this.map = null; - - this.lightMap = null; - this.lightMapIntensity = 1.0; - - this.aoMap = null; - this.aoMapIntensity = 1.0; - - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; - - this.specularMap = null; - - this.alphaMap = null; - - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; - - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - - this.map = source.map; - - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; - - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; - - this.specularMap = source.specularMap; - - this.alphaMap = source.alphaMap; - - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; - - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; - - return this; - - } - - } - - MeshLambertMaterial.prototype.isMeshLambertMaterial = true; - - /** - * parameters = { - * color: , - * opacity: , - * - * matcap: new THREE.Texture( ), - * - * map: new THREE.Texture( ), - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalMapType: THREE.TangentSpaceNormalMap, - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * alphaMap: new THREE.Texture( ), - * - * flatShading: - * } - */ - - class MeshMatcapMaterial extends Material { - - constructor( parameters ) { - - super(); - - this.defines = { 'MATCAP': '' }; - - this.type = 'MeshMatcapMaterial'; - - this.color = new Color( 0xffffff ); // diffuse - - this.matcap = null; - - this.map = null; - - this.bumpMap = null; - this.bumpScale = 1; - - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); - - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; - - this.alphaMap = null; - - this.flatShading = false; - - this.setValues( parameters ); - - } - - - copy( source ) { - - super.copy( source ); - - this.defines = { 'MATCAP': '' }; - - this.color.copy( source.color ); - - this.matcap = source.matcap; - - this.map = source.map; - - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; - - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); - - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; - - this.alphaMap = source.alphaMap; - - this.flatShading = source.flatShading; - - return this; - - } - - } - - MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true; - - /** - * parameters = { - * color: , - * opacity: , - * - * linewidth: , - * - * scale: , - * dashSize: , - * gapSize: - * } - */ - - class LineDashedMaterial extends LineBasicMaterial { - - constructor( parameters ) { - - super(); - - this.type = 'LineDashedMaterial'; - - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - - this.setValues( parameters ); - - } - - copy( source ) { - - super.copy( source ); - - this.scale = source.scale; - this.dashSize = source.dashSize; - this.gapSize = source.gapSize; - - return this; - - } - - } - - LineDashedMaterial.prototype.isLineDashedMaterial = true; - - var Materials = /*#__PURE__*/Object.freeze({ - __proto__: null, - ShadowMaterial: ShadowMaterial, - SpriteMaterial: SpriteMaterial, - RawShaderMaterial: RawShaderMaterial, - ShaderMaterial: ShaderMaterial, - PointsMaterial: PointsMaterial, - MeshPhysicalMaterial: MeshPhysicalMaterial, - MeshStandardMaterial: MeshStandardMaterial, - MeshPhongMaterial: MeshPhongMaterial, - MeshToonMaterial: MeshToonMaterial, - MeshNormalMaterial: MeshNormalMaterial, - MeshLambertMaterial: MeshLambertMaterial, - MeshDepthMaterial: MeshDepthMaterial, - MeshDistanceMaterial: MeshDistanceMaterial, - MeshBasicMaterial: MeshBasicMaterial, - MeshMatcapMaterial: MeshMatcapMaterial, - LineDashedMaterial: LineDashedMaterial, - LineBasicMaterial: LineBasicMaterial, - Material: Material - }); - - const 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 ); - - }, - - // 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 ]; - - } - - const n = times.length; - const result = new Array( n ); - for ( let 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 ) { - - const nValues = values.length; - const result = new values.constructor( nValues ); - - for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { - - const srcOffset = order[ i ] * stride; - - for ( let j = 0; j !== stride; ++ j ) { - - result[ dstOffset ++ ] = values[ srcOffset + j ]; - - } - - } - - return result; - - }, - - // function for parsing AOS keyframe formats - flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { - - let i = 1, key = jsonKeys[ 0 ]; - - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { - - key = jsonKeys[ i ++ ]; - - } - - if ( key === undefined ) return; // no data - - let 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 { - - value = key[ valuePropertyName ]; - - if ( value !== undefined ) { - - times.push( key.time ); - values.push( value ); - - } - - key = jsonKeys[ i ++ ]; - - } while ( key !== undefined ); - - } - - }, - - subclip: function ( sourceClip, name, startFrame, endFrame, fps = 30 ) { - - const clip = sourceClip.clone(); - - clip.name = name; - - const tracks = []; - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - const track = clip.tracks[ i ]; - const valueSize = track.getValueSize(); - - const times = []; - const values = []; - - for ( let j = 0; j < track.times.length; ++ j ) { - - const frame = track.times[ j ] * fps; - - if ( frame < startFrame || frame >= endFrame ) continue; - - times.push( track.times[ j ] ); - - for ( let k = 0; k < valueSize; ++ k ) { - - values.push( track.values[ j * valueSize + k ] ); - - } - - } - - if ( times.length === 0 ) continue; - - track.times = AnimationUtils.convertArray( times, track.times.constructor ); - track.values = AnimationUtils.convertArray( values, track.values.constructor ); - - tracks.push( track ); - - } - - clip.tracks = tracks; - - // find minimum .times value across all tracks in the trimmed clip - - let minStartTime = Infinity; - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { - - minStartTime = clip.tracks[ i ].times[ 0 ]; - - } - - } - - // shift all tracks such that clip begins at t=0 - - for ( let i = 0; i < clip.tracks.length; ++ i ) { - - clip.tracks[ i ].shift( - 1 * minStartTime ); - - } - - clip.resetDuration(); - - return clip; - - }, - - makeClipAdditive: function ( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { - - if ( fps <= 0 ) fps = 30; - - const numTracks = referenceClip.tracks.length; - const referenceTime = referenceFrame / fps; - - // Make each track's values relative to the values at the reference frame - for ( let i = 0; i < numTracks; ++ i ) { - - const referenceTrack = referenceClip.tracks[ i ]; - const referenceTrackType = referenceTrack.ValueTypeName; - - // Skip this track if it's non-numeric - if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; - - // Find the track in the target clip whose name and type matches the reference track - const targetTrack = targetClip.tracks.find( function ( track ) { - - return track.name === referenceTrack.name - && track.ValueTypeName === referenceTrackType; - - } ); - - if ( targetTrack === undefined ) continue; - - let referenceOffset = 0; - const referenceValueSize = referenceTrack.getValueSize(); - - if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - - referenceOffset = referenceValueSize / 3; - - } - - let targetOffset = 0; - const targetValueSize = targetTrack.getValueSize(); - - if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { - - targetOffset = targetValueSize / 3; - - } - - const lastIndex = referenceTrack.times.length - 1; - let referenceValue; - - // Find the value to subtract out of the track - if ( referenceTime <= referenceTrack.times[ 0 ] ) { - - // Reference frame is earlier than the first keyframe, so just use the first keyframe - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex ); - - } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { - - // Reference frame is after the last keyframe, so just use the last keyframe - const startIndex = lastIndex * referenceValueSize + referenceOffset; - const endIndex = startIndex + referenceValueSize - referenceOffset; - referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex, endIndex ); - - } else { - - // Interpolate to the reference value - const interpolant = referenceTrack.createInterpolant(); - const startIndex = referenceOffset; - const endIndex = referenceValueSize - referenceOffset; - interpolant.evaluate( referenceTime ); - referenceValue = AnimationUtils.arraySlice( interpolant.resultBuffer, startIndex, endIndex ); - - } - - // Conjugate the quaternion - if ( referenceTrackType === 'quaternion' ) { - - const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); - referenceQuat.toArray( referenceValue ); - - } - - // Subtract the reference value from all of the track values - - const numTimes = targetTrack.times.length; - for ( let j = 0; j < numTimes; ++ j ) { - - const valueStart = j * targetValueSize + targetOffset; - - if ( referenceTrackType === 'quaternion' ) { - - // Multiply the conjugate for quaternion track types - Quaternion.multiplyQuaternionsFlat( - targetTrack.values, - valueStart, - referenceValue, - 0, - targetTrack.values, - valueStart - ); - - } else { - - const valueEnd = targetValueSize - targetOffset * 2; - - // Subtract each value for all other numeric track types - for ( let k = 0; k < valueEnd; ++ k ) { - - targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; - - } - - } - - } - - } - - targetClip.blendMode = AdditiveAnimationBlendMode; - - return targetClip; - - } - - }; - - /** - * 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 - * - */ - - class Interpolant { - - constructor( 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; - - this.settings = null; - this.DefaultSettings_ = {}; - - } - - evaluate( t ) { - - const pp = this.parameterPositions; - let i1 = this._cachedIndex, - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; - - validate_interval: { - - seek: { - - let right; - - linear_scan: { - - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { - - for ( let 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? - - const t1global = pp[ 1 ]; - - if ( t < t1global ) { - - i1 = 2; // + 1, using the scan for the details - t0 = t1global; - - } - - // linear reverse scan - - for ( let 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 ) { - - const 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 ); - - } - - getSettings_() { - - return this.settings || this.DefaultSettings_; - - } - - copySampleValue_( index ) { - - // copies a sample value to the result buffer - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = values[ offset + i ]; - - } - - return result; - - } - - // Template methods for derived classes: - - interpolate_( /* i1, t0, t, t1 */ ) { - - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer - - } - - intervalChanged_( /* i1, t0, t1 */ ) { - - // empty - - } - - } - - // ALIAS DEFINITIONS - - Interpolant.prototype.beforeStart_ = Interpolant.prototype.copySampleValue_; - Interpolant.prototype.afterEnd_ = Interpolant.prototype.copySampleValue_; - - /** - * 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. - */ - - class CubicInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; - - this.DefaultSettings_ = { - - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - - }; - - } - - intervalChanged_( i1, t0, t1 ) { - - const pp = this.parameterPositions; - let 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; - - } - - } - - if ( tNext === undefined ) { - - switch ( this.getSettings_().endingEnd ) { - - case ZeroSlopeEnding: - - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; - - 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; - - } - - } - - const 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_( i1, t0, t, t1 ) { - - const 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 - - const sP = - wP * ppp + 2 * wP * pp - wP * p; - const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - const sN = wN * ppp - wN * pp; - - // combine data linearly - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; - - } - - return result; - - } - - } - - class LinearInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - offset1 = i1 * stride, - offset0 = offset1 - stride, - - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; - - for ( let i = 0; i !== stride; ++ i ) { - - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; - - } - - return result; - - } - - } - - /** - * - * Interpolant that evaluates to the sample value at the position preceeding - * the parameter. - */ - - class DiscreteInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1 /*, t0, t, t1 */ ) { - - return this.copySampleValue_( i1 - 1 ); - - } - - } - - class KeyframeTrack { - - constructor( name, times, values, interpolation ) { - - 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.name = name; - - this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); - this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); - - this.setInterpolation( interpolation || this.DefaultInterpolation ); - - } - - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): - - static toJSON( track ) { - - const trackType = track.constructor; - - let json; - - // derived classes can define a static toJSON method - if ( trackType.toJSON !== this.toJSON ) { - - json = trackType.toJSON( track ); - - } else { - - // by default, we assume the data can be serialized as-is - json = { - - 'name': track.name, - 'times': AnimationUtils.convertArray( track.times, Array ), - 'values': AnimationUtils.convertArray( track.values, Array ) - - }; - - const interpolation = track.getInterpolation(); - - if ( interpolation !== track.DefaultInterpolation ) { - - json.interpolation = interpolation; - - } - - } - - json.type = track.ValueTypeName; // mandatory - - return json; - - } - - InterpolantFactoryMethodDiscrete( result ) { - - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - InterpolantFactoryMethodLinear( result ) { - - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - InterpolantFactoryMethodSmooth( result ) { - - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - setInterpolation( interpolation ) { - - let factoryMethod; - - switch ( interpolation ) { - - case InterpolateDiscrete: - - factoryMethod = this.InterpolantFactoryMethodDiscrete; - - break; - - case InterpolateLinear: - - factoryMethod = this.InterpolantFactoryMethodLinear; - - break; - - case InterpolateSmooth: - - factoryMethod = this.InterpolantFactoryMethodSmooth; - - break; - - } - - if ( factoryMethod === undefined ) { - - const message = 'unsupported interpolation for ' + - this.ValueTypeName + ' keyframe track named ' + this.name; - - if ( this.createInterpolant === undefined ) { - - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { - - this.setInterpolation( this.DefaultInterpolation ); - - } else { - - throw new Error( message ); // fatal, in this case - - } - - } - - console.warn( 'THREE.KeyframeTrack:', message ); - return this; - - } - - this.createInterpolant = factoryMethod; - - return this; - - } - - getInterpolation() { - - switch ( this.createInterpolant ) { - - case this.InterpolantFactoryMethodDiscrete: - - return InterpolateDiscrete; - - case this.InterpolantFactoryMethodLinear: - - return InterpolateLinear; - - case this.InterpolantFactoryMethodSmooth: - - return InterpolateSmooth; - - } - - } - - getValueSize() { - - return this.values.length / this.times.length; - - } - - // move all keyframes either forwards or backwards in time - shift( timeOffset ) { - - if ( timeOffset !== 0.0 ) { - - const times = this.times; - - for ( let i = 0, n = times.length; i !== n; ++ i ) { - - times[ i ] += timeOffset; - - } - - } - - return this; - - } - - // scale all keyframe times by a factor (useful for frame <-> seconds conversions) - scale( timeScale ) { - - if ( timeScale !== 1.0 ) { - - const times = this.times; - - for ( let i = 0, n = times.length; i !== n; ++ i ) { - - times[ i ] *= timeScale; - - } - - } - - return this; - - } - - // 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( startTime, endTime ) { - - const times = this.times, - nKeys = times.length; - - let from = 0, - to = nKeys - 1; - - while ( from !== nKeys && times[ from ] < startTime ) { - - ++ from; - - } - - while ( to !== - 1 && times[ to ] > endTime ) { - - -- to; - - } - - ++ to; // inclusive -> exclusive bound - - if ( from !== 0 || to !== nKeys ) { - - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) { - - to = Math.max( to, 1 ); - from = to - 1; - - } - - const stride = this.getValueSize(); - this.times = AnimationUtils.arraySlice( times, from, to ); - this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); - - } - - return this; - - } - - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate() { - - let valid = true; - - const valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { - - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; - - } - - const times = this.times, - values = this.values, - - nKeys = times.length; - - if ( nKeys === 0 ) { - - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; - - } - - let prevTime = null; - - for ( let i = 0; i !== nKeys; i ++ ) { - - const currTime = times[ i ]; - - if ( typeof currTime === 'number' && isNaN( currTime ) ) { - - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; - - } - - if ( prevTime !== null && prevTime > currTime ) { - - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; - - } - - prevTime = currTime; - - } - - if ( values !== undefined ) { - - if ( AnimationUtils.isTypedArray( values ) ) { - - for ( let i = 0, n = values.length; i !== n; ++ i ) { - - const value = values[ i ]; - - if ( isNaN( value ) ) { - - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; - - } - - } - - } - - } - - return valid; - - } - - // 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() { - - // times or values may be shared with other tracks, so overwriting is unsafe - const times = AnimationUtils.arraySlice( this.times ), - values = AnimationUtils.arraySlice( this.values ), - stride = this.getValueSize(), - - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - - lastIndex = times.length - 1; - - let writeIndex = 1; - - for ( let i = 1; i < lastIndex; ++ i ) { - - let keep = false; - - const time = times[ i ]; - const timeNext = times[ i + 1 ]; - - // remove adjacent keyframes scheduled at the same time - - if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { - - if ( ! smoothInterpolation ) { - - // remove unnecessary keyframes same as their neighbors - - const offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; - - for ( let j = 0; j !== stride; ++ j ) { - - const value = values[ offset + j ]; - - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { - - keep = true; - break; - - } - - } - - } else { - - keep = true; - - } - - } - - // in-place compaction - - if ( keep ) { - - if ( i !== writeIndex ) { - - times[ writeIndex ] = times[ i ]; - - const readOffset = i * stride, - writeOffset = writeIndex * stride; - - for ( let j = 0; j !== stride; ++ j ) { - - values[ writeOffset + j ] = values[ readOffset + j ]; - - } - - } - - ++ writeIndex; - - } - - } - - // flush last keyframe (compaction looks ahead) - - if ( lastIndex > 0 ) { - - times[ writeIndex ] = times[ lastIndex ]; - - for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { - - values[ writeOffset + j ] = values[ readOffset + j ]; - - } - - ++ writeIndex; - - } - - if ( writeIndex !== times.length ) { - - this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); - this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); - - } else { - - this.times = times; - this.values = values; - - } - - return this; - - } - - clone() { - - const times = AnimationUtils.arraySlice( this.times, 0 ); - const values = AnimationUtils.arraySlice( this.values, 0 ); - - const TypedKeyframeTrack = this.constructor; - const track = new TypedKeyframeTrack( this.name, times, values ); - - // Interpolant argument to constructor is not saved, so copy the factory method directly. - track.createInterpolant = this.createInterpolant; - - return track; - - } - - } - - KeyframeTrack.prototype.TimeBufferType = Float32Array; - KeyframeTrack.prototype.ValueBufferType = Float32Array; - KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; - - /** - * A Track of Boolean keyframe values. - */ - class BooleanKeyframeTrack extends KeyframeTrack {} - - BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; - BooleanKeyframeTrack.prototype.ValueBufferType = Array; - BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; - BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; - BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - - /** - * A Track of keyframe values that represent color. - */ - class ColorKeyframeTrack extends KeyframeTrack {} - - ColorKeyframeTrack.prototype.ValueTypeName = 'color'; - - /** - * A Track of numeric keyframe values. - */ - class NumberKeyframeTrack extends KeyframeTrack {} - - NumberKeyframeTrack.prototype.ValueTypeName = 'number'; - - /** - * Spherical linear unit quaternion interpolant. - */ - - class QuaternionLinearInterpolant extends Interpolant { - - constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - - super( parameterPositions, sampleValues, sampleSize, resultBuffer ); - - } - - interpolate_( i1, t0, t, t1 ) { - - const result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - - alpha = ( t - t0 ) / ( t1 - t0 ); - - let offset = i1 * stride; - - for ( let end = offset + stride; offset !== end; offset += 4 ) { - - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); - - } - - return result; - - } - - } - - /** - * A Track of quaternion keyframe values. - */ - class QuaternionKeyframeTrack extends KeyframeTrack { - - InterpolantFactoryMethodLinear( result ) { - - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); - - } - - } - - QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; - // ValueBufferType is inherited - QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; - QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - - /** - * A Track that interpolates Strings - */ - class StringKeyframeTrack extends KeyframeTrack {} - - StringKeyframeTrack.prototype.ValueTypeName = 'string'; - StringKeyframeTrack.prototype.ValueBufferType = Array; - StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; - StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; - StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; - - /** - * A Track of vectored keyframe values. - */ - class VectorKeyframeTrack extends KeyframeTrack {} - - VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; - - class AnimationClip { - - constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) { - - this.name = name; - this.tracks = tracks; - this.duration = duration; - this.blendMode = blendMode; - - this.uuid = generateUUID(); - - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { - - this.resetDuration(); - - } - - } - - - static parse( json ) { - - const tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); - - for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { - - tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); - - } - - const clip = new this( json.name, json.duration, tracks, json.blendMode ); - clip.uuid = json.uuid; - - return clip; - - } - - static toJSON( clip ) { - - const tracks = [], - clipTracks = clip.tracks; - - const json = { - - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks, - 'uuid': clip.uuid, - 'blendMode': clip.blendMode - - }; - - for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { - - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); - - } - - return json; - - } - - static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { - - const numMorphTargets = morphTargetSequence.length; - const tracks = []; - - for ( let i = 0; i < numMorphTargets; i ++ ) { - - let times = []; - let values = []; - - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); - - values.push( 0, 1, 0 ); - - const order = AnimationUtils.getKeyframeOrder( times ); - times = AnimationUtils.sortedArray( times, 1, order ); - values = AnimationUtils.sortedArray( values, 1, order ); - - // 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 ] ); - - } - - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); - - } - - return new this( name, - 1, tracks ); - - } - - static findByName( objectOrClipArray, name ) { - - let clipArray = objectOrClipArray; - - if ( ! Array.isArray( objectOrClipArray ) ) { - - const o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; - - } - - for ( let i = 0; i < clipArray.length; i ++ ) { - - if ( clipArray[ i ].name === name ) { - - return clipArray[ i ]; - - } - - } - - return null; - - } - - static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { - - const animationToMorphTargets = {}; - - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - const pattern = /^([\w-]*?)([\d]+)$/; - - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { - - const morphTarget = morphTargets[ i ]; - const parts = morphTarget.name.match( pattern ); - - if ( parts && parts.length > 1 ) { - - const name = parts[ 1 ]; - - let animationMorphTargets = animationToMorphTargets[ name ]; - - if ( ! animationMorphTargets ) { - - animationToMorphTargets[ name ] = animationMorphTargets = []; - - } - - animationMorphTargets.push( morphTarget ); - - } - - } - - const clips = []; - - for ( const name in animationToMorphTargets ) { - - clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); - - } - - return clips; - - } - - // parse the animation.hierarchy format - static parseAnimation( animation, bones ) { - - if ( ! animation ) { - - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; - - } - - const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { - - const times = []; - const 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 ) ); - - } - - } - - }; - - const tracks = []; - - const clipName = animation.name || 'default'; - const fps = animation.fps || 30; - const blendMode = animation.blendMode; - - // automatic length determination in AnimationClip. - let duration = animation.length || - 1; - - const hierarchyTracks = animation.hierarchy || []; - - for ( let h = 0; h < hierarchyTracks.length; h ++ ) { - - const animationKeys = hierarchyTracks[ h ].keys; - - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; - - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { - - // figure out all morph targets used in this track - const morphTargetNames = {}; - - let k; - - for ( k = 0; k < animationKeys.length; k ++ ) { - - if ( animationKeys[ k ].morphTargets ) { - - for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - - } - - } - - } - - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( const morphTargetName in morphTargetNames ) { - - const times = []; - const values = []; - - for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { - - const animationKey = animationKeys[ k ]; - - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - - } - - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - - } - - duration = morphTargetNames.length * ( fps || 1.0 ); - - } else { - - // ...assume skeletal animation - - const boneName = '.bones[' + bones[ h ].name + ']'; - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); - - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); - - } - - } - - if ( tracks.length === 0 ) { - - return null; - - } - - const clip = new this( clipName, duration, tracks, blendMode ); - - return clip; - - } - - resetDuration() { - - const tracks = this.tracks; - let duration = 0; - - for ( let i = 0, n = tracks.length; i !== n; ++ i ) { - - const track = this.tracks[ i ]; - - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - - } - - this.duration = duration; - - return this; - - } - - trim() { - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].trim( 0, this.duration ); - - } - - return this; - - } - - validate() { - - let valid = true; - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - valid = valid && this.tracks[ i ].validate(); - - } - - return valid; - - } - - optimize() { - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - this.tracks[ i ].optimize(); - - } - - return this; - - } - - clone() { - - const tracks = []; - - for ( let i = 0; i < this.tracks.length; i ++ ) { - - tracks.push( this.tracks[ i ].clone() ); - - } - - return new this.constructor( this.name, this.duration, tracks, this.blendMode ); - - } - - toJSON() { - - return this.constructor.toJSON( this ); - - } - - } - - function getTrackTypeForValueTypeName( typeName ) { - - switch ( typeName.toLowerCase() ) { - - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': - - return NumberKeyframeTrack; - - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': - - return VectorKeyframeTrack; - - case 'color': - - return ColorKeyframeTrack; - - case 'quaternion': - - return QuaternionKeyframeTrack; - - case 'bool': - case 'boolean': - - return BooleanKeyframeTrack; - - case 'string': - - return StringKeyframeTrack; - - } - - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - - } - - function parseKeyframeTrack( json ) { - - if ( json.type === undefined ) { - - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); - - } - - const trackType = getTrackTypeForValueTypeName( json.type ); - - if ( json.times === undefined ) { - - const times = [], values = []; - - AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); - - json.times = times; - json.values = values; - - } - - // derived classes can define a static parse method - if ( trackType.parse !== undefined ) { - - return trackType.parse( json ); - - } else { - - // by default, we assume a constructor compatible with the base - return new trackType( json.name, json.times, json.values, json.interpolation ); - - } - - } - - const Cache = { - - enabled: false, - - files: {}, - - add: function ( key, file ) { - - if ( this.enabled === false ) return; - - // console.log( 'THREE.Cache', 'Adding key:', key ); - - this.files[ key ] = file; - - }, - - get: function ( key ) { - - if ( this.enabled === false ) return; - - // console.log( 'THREE.Cache', 'Checking key:', key ); - - return this.files[ key ]; - - }, - - remove: function ( key ) { - - delete this.files[ key ]; - - }, - - clear: function () { - - this.files = {}; - - } - - }; - - class LoadingManager { - - constructor( onLoad, onProgress, onError ) { - - const scope = this; - - let isLoading = false; - let itemsLoaded = 0; - let itemsTotal = 0; - let urlModifier = undefined; - const handlers = []; - - // Refer to #5689 for the reason why we don't set .onStart - // in the constructor - - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; - - this.itemStart = function ( url ) { - - itemsTotal ++; - - if ( isLoading === false ) { - - if ( scope.onStart !== undefined ) { - - scope.onStart( url, itemsLoaded, itemsTotal ); - - } - - } - - isLoading = true; - - }; - - this.itemEnd = function ( url ) { - - itemsLoaded ++; - - if ( scope.onProgress !== undefined ) { - - scope.onProgress( url, itemsLoaded, itemsTotal ); - - } - - if ( itemsLoaded === itemsTotal ) { - - isLoading = false; - - if ( scope.onLoad !== undefined ) { - - scope.onLoad(); - - } - - } - - }; - - this.itemError = function ( url ) { - - if ( scope.onError !== undefined ) { - - scope.onError( url ); - - } - - }; - - this.resolveURL = function ( url ) { - - if ( urlModifier ) { - - return urlModifier( url ); - - } - - return url; - - }; - - this.setURLModifier = function ( transform ) { - - urlModifier = transform; - - return this; - - }; - - this.addHandler = function ( regex, loader ) { - - handlers.push( regex, loader ); - - return this; - - }; - - this.removeHandler = function ( regex ) { - - const index = handlers.indexOf( regex ); - - if ( index !== - 1 ) { - - handlers.splice( index, 2 ); - - } - - return this; - - }; - - this.getHandler = function ( file ) { - - for ( let i = 0, l = handlers.length; i < l; i += 2 ) { - - const regex = handlers[ i ]; - const loader = handlers[ i + 1 ]; - - if ( regex.global ) regex.lastIndex = 0; // see #17920 - - if ( regex.test( file ) ) { - - return loader; - - } - - } - - return null; - - }; - - } - - } - - const DefaultLoadingManager = new LoadingManager(); - - class Loader { - - constructor( manager ) { - - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - - this.crossOrigin = 'anonymous'; - this.withCredentials = false; - this.path = ''; - this.resourcePath = ''; - this.requestHeader = {}; - - } - - load( /* url, onLoad, onProgress, onError */ ) {} - - loadAsync( url, onProgress ) { - - const scope = this; - - return new Promise( function ( resolve, reject ) { - - scope.load( url, resolve, onProgress, reject ); - - } ); - - } - - parse( /* data */ ) {} - - setCrossOrigin( crossOrigin ) { - - this.crossOrigin = crossOrigin; - return this; - - } - - setWithCredentials( value ) { - - this.withCredentials = value; - return this; - - } - - setPath( path ) { - - this.path = path; - return this; - - } - - setResourcePath( resourcePath ) { - - this.resourcePath = resourcePath; - return this; - - } - - setRequestHeader( requestHeader ) { - - this.requestHeader = requestHeader; - return this; - - } - - } - - const loading = {}; - - class FileLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - if ( url === undefined ) url = ''; - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const scope = this; - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - // Check if request is duplicate - - if ( loading[ url ] !== undefined ) { - - loading[ url ].push( { - - onLoad: onLoad, - onProgress: onProgress, - onError: onError - - } ); - - return; - - } - - // Check for data: URI - const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; - const dataUriRegexResult = url.match( dataUriRegex ); - let request; - - // Safari can not handle Data URIs through XMLHttpRequest so process manually - if ( dataUriRegexResult ) { - - const mimeType = dataUriRegexResult[ 1 ]; - const isBase64 = !! dataUriRegexResult[ 2 ]; - - let data = dataUriRegexResult[ 3 ]; - data = decodeURIComponent( data ); - - if ( isBase64 ) data = atob( data ); - - try { - - let response; - const responseType = ( this.responseType || '' ).toLowerCase(); - - switch ( responseType ) { - - case 'arraybuffer': - case 'blob': - - const view = new Uint8Array( data.length ); - - for ( let i = 0; i < data.length; i ++ ) { - - view[ i ] = data.charCodeAt( i ); - - } - - if ( responseType === 'blob' ) { - - response = new Blob( [ view.buffer ], { type: mimeType } ); - - } else { - - response = view.buffer; - - } - - break; - - case 'document': - - const parser = new DOMParser(); - response = parser.parseFromString( data, mimeType ); - - break; - - case 'json': - - response = JSON.parse( data ); - - break; - - default: // 'text' or other - - response = data; - - break; - - } - - // Wait for next browser tick like standard XMLHttpRequest event dispatching does - setTimeout( function () { - - if ( onLoad ) onLoad( response ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - } catch ( error ) { - - // Wait for next browser tick like standard XMLHttpRequest event dispatching does - setTimeout( function () { - - if ( onError ) onError( error ); - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - }, 0 ); - - } - - } else { - - // Initialise array for duplicate requests - - loading[ url ] = []; - - loading[ url ].push( { - - onLoad: onLoad, - onProgress: onProgress, - onError: onError - - } ); - - request = new XMLHttpRequest(); - - request.open( 'GET', url, true ); - - request.addEventListener( 'load', function ( event ) { - - const response = this.response; - - const callbacks = loading[ url ]; - - delete loading[ url ]; - - if ( this.status === 200 || this.status === 0 ) { - - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. - - if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); - - // Add to cache only on HTTP success, so that we do not cache - // error response bodies as proper responses to requests. - Cache.add( url, response ); - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onLoad ) callback.onLoad( response ); - - } - - scope.manager.itemEnd( url ); - - } else { - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( event ); - - } - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } - - }, false ); - - request.addEventListener( 'progress', function ( event ) { - - const callbacks = loading[ url ]; - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onProgress ) callback.onProgress( event ); - - } - - }, false ); - - request.addEventListener( 'error', function ( event ) { - - const callbacks = loading[ url ]; - - delete loading[ url ]; - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( event ); - - } - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - }, false ); - - request.addEventListener( 'abort', function ( event ) { - - const callbacks = loading[ url ]; - - delete loading[ url ]; - - for ( let i = 0, il = callbacks.length; i < il; i ++ ) { - - const callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( event ); - - } - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - }, false ); - - if ( this.responseType !== undefined ) request.responseType = this.responseType; - if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; - - if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); - - for ( const header in this.requestHeader ) { - - request.setRequestHeader( header, this.requestHeader[ header ] ); - - } - - request.send( null ); - - } - - scope.manager.itemStart( url ); - - return request; - - } - - setResponseType( value ) { - - this.responseType = value; - return this; - - } - - setMimeType( value ) { - - this.mimeType = value; - return this; - - } - - } - - class AnimationLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const animations = []; - - for ( let i = 0; i < json.length; i ++ ) { - - const clip = AnimationClip.parse( json[ i ] ); - - animations.push( clip ); - - } - - return animations; - - } - - } - - /** - * Abstract Base class to block based textures loader (dds, pvr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - - class CompressedTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const images = []; - - const texture = new CompressedTexture(); - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - - let loaded = 0; - - function loadTexture( i ) { - - loader.load( url[ i ], function ( buffer ) { - - const texDatas = scope.parse( buffer, true ); - - images[ i ] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; - - loaded += 1; - - if ( loaded === 6 ) { - - if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; - - texture.image = images; - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, onProgress, onError ); - - } - - if ( Array.isArray( url ) ) { - - for ( let i = 0, il = url.length; i < il; ++ i ) { - - loadTexture( i ); - - } - - } else { - - // compressed cubemap texture stored in a single DDS file - - loader.load( url, function ( buffer ) { - - const texDatas = scope.parse( buffer, true ); - - if ( texDatas.isCubemap ) { - - const faces = texDatas.mipmaps.length / texDatas.mipmapCount; - - for ( let f = 0; f < faces; f ++ ) { - - images[ f ] = { mipmaps: [] }; - - for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { - - images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); - images[ f ].format = texDatas.format; - images[ f ].width = texDatas.width; - images[ f ].height = texDatas.height; - - } - - } - - texture.image = images; - - } else { - - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; - - } - - if ( texDatas.mipmapCount === 1 ) { - - texture.minFilter = LinearFilter; - - } - - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - }, onProgress, onError ); - - } - - return texture; - - } - - } - - class ImageLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const scope = this; - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - const image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' ); - - function onImageLoad() { - - image.removeEventListener( 'load', onImageLoad, false ); - image.removeEventListener( 'error', onImageError, false ); - - Cache.add( url, this ); - - if ( onLoad ) onLoad( this ); - - scope.manager.itemEnd( url ); - - } - - function onImageError( event ) { - - image.removeEventListener( 'load', onImageLoad, false ); - image.removeEventListener( 'error', onImageError, false ); - - if ( onError ) onError( event ); - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } - - image.addEventListener( 'load', onImageLoad, false ); - image.addEventListener( 'error', onImageError, false ); - - if ( url.substr( 0, 5 ) !== 'data:' ) { - - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; - - } - - scope.manager.itemStart( url ); - - image.src = url; - - return image; - - } - - } - - class CubeTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( urls, onLoad, onProgress, onError ) { - - const texture = new CubeTexture(); - - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - let loaded = 0; - - function loadTexture( i ) { - - loader.load( urls[ i ], function ( image ) { - - texture.images[ i ] = image; - - loaded ++; - - if ( loaded === 6 ) { - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - } - - }, undefined, onError ); - - } - - for ( let i = 0; i < urls.length; ++ i ) { - - loadTexture( i ); - - } - - return texture; - - } - - } - - /** - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) - * - * Sub classes have to implement the parse() method which will be used in load(). - */ - - class DataTextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const texture = new DataTexture(); - - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setRequestHeader( this.requestHeader ); - loader.setPath( this.path ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( buffer ) { - - const texData = scope.parse( buffer ); - - if ( ! texData ) return; - - if ( texData.image !== undefined ) { - - texture.image = texData.image; - - } else if ( texData.data !== undefined ) { - - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; - - } - - texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; - texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; - - texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; - texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; - - texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; - - if ( texData.encoding !== undefined ) { - - texture.encoding = texData.encoding; - - } - - if ( texData.flipY !== undefined ) { - - texture.flipY = texData.flipY; - - } - - if ( texData.format !== undefined ) { - - texture.format = texData.format; - - } - - if ( texData.type !== undefined ) { - - texture.type = texData.type; - - } - - if ( texData.mipmaps !== undefined ) { - - texture.mipmaps = texData.mipmaps; - texture.minFilter = LinearMipmapLinearFilter; // presumably... - - } - - if ( texData.mipmapCount === 1 ) { - - texture.minFilter = LinearFilter; - - } - - if ( texData.generateMipmaps !== undefined ) { - - texture.generateMipmaps = texData.generateMipmaps; - - } - - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture, texData ); - - }, onProgress, onError ); - - - return texture; - - } - - } - - class TextureLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const texture = new Texture(); - - const loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); - - loader.load( url, function ( image ) { - - texture.image = image; - - // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. - const isJPEG = url.search( /\.jpe?g($|\?)/i ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; - - texture.format = isJPEG ? RGBFormat : RGBAFormat; - texture.needsUpdate = true; - - if ( onLoad !== undefined ) { - - onLoad( texture ); - - } - - }, onProgress, onError ); - - return texture; - - } - - } - - /************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ - - class CurvePath extends Curve { - - constructor() { - - super(); - - this.type = 'CurvePath'; - - this.curves = []; - this.autoClose = false; // Automatically closes the path - - } - - add( curve ) { - - this.curves.push( curve ); - - } - - closePath() { - - // Add a line curve if start and end of lines are not connected - const startPoint = this.curves[ 0 ].getPoint( 0 ); - const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); - - if ( ! startPoint.equals( endPoint ) ) { - - this.curves.push( new LineCurve( endPoint, startPoint ) ); - - } - - } - - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: - - // 1. Length of each sub path have to be known - // 2. Locate and identify type of curve - // 3. Get t for the curve - // 4. Return curve.getPointAt(t') - - getPoint( t ) { - - const d = t * this.getLength(); - const curveLengths = this.getCurveLengths(); - let i = 0; - - // To think about boundaries points. - - while ( i < curveLengths.length ) { - - if ( curveLengths[ i ] >= d ) { - - const diff = curveLengths[ i ] - d; - const curve = this.curves[ i ]; - - const segmentLength = curve.getLength(); - const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; - - return curve.getPointAt( u ); - - } - - i ++; - - } - - return null; - - // loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { - - points.push( points[ 0 ] ); - - } - - return points; - - } - - copy( source ) { - - super.copy( source ); - - this.curves = []; - - for ( let i = 0, l = source.curves.length; i < l; i ++ ) { - - const curve = source.curves[ i ]; - - this.curves.push( curve.clone() ); - - } - - this.autoClose = source.autoClose; - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.autoClose = this.autoClose; - data.curves = []; - - for ( let i = 0, l = this.curves.length; i < l; i ++ ) { - - const curve = this.curves[ i ]; - data.curves.push( curve.toJSON() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.autoClose = json.autoClose; - this.curves = []; - - for ( let i = 0, l = json.curves.length; i < l; i ++ ) { - - const curve = json.curves[ i ]; - this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); - - } - - return this; - - } - - } - - class Path extends CurvePath { - - constructor( points ) { - - super(); - this.type = 'Path'; - - this.currentPoint = new Vector2(); - - if ( points ) { - - this.setFromPoints( points ); - - } - - } - - setFromPoints( points ) { - - this.moveTo( points[ 0 ].x, points[ 0 ].y ); - - for ( let i = 1, l = points.length; i < l; i ++ ) { - - this.lineTo( points[ i ].x, points[ i ].y ); - - } - - return this; - - } - - moveTo( x, y ) { - - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? - - return this; - - } - - lineTo( x, y ) { - - const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); - - this.currentPoint.set( x, y ); - - return this; - - } - - quadraticCurveTo( aCPx, aCPy, aX, aY ) { - - const curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); - - this.currentPoint.set( aX, aY ); - - return this; - - } - - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - const curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); - - this.currentPoint.set( aX, aY ); - - return this; - - } - - splineThru( pts /*Array of Vector*/ ) { - - const npts = [ this.currentPoint.clone() ].concat( pts ); - - const curve = new SplineCurve( npts ); - this.curves.push( curve ); - - this.currentPoint.copy( pts[ pts.length - 1 ] ); - - return this; - - } - - arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - const x0 = this.currentPoint.x; - const y0 = this.currentPoint.y; - - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); - - return this; - - } - - absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - - return this; - - } - - ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - const x0 = this.currentPoint.x; - const y0 = this.currentPoint.y; - - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - - return this; - - } - - absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - - const 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 - const firstPoint = curve.getPoint( 0 ); - - if ( ! firstPoint.equals( this.currentPoint ) ) { - - this.lineTo( firstPoint.x, firstPoint.y ); - - } - - } - - this.curves.push( curve ); - - const lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); - - return this; - - } - - copy( source ) { - - super.copy( source ); - - this.currentPoint.copy( source.currentPoint ); - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.currentPoint = this.currentPoint.toArray(); - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.currentPoint.fromArray( json.currentPoint ); - - return this; - - } - - } - - class Shape extends Path { - - constructor( points ) { - - super( points ); - - this.uuid = generateUUID(); - - this.type = 'Shape'; - - this.holes = []; - - } - - getPointsHoles( divisions ) { - - const holesPts = []; - - for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); - - } - - return holesPts; - - } - - // get points of shape and holes (keypoints based on segments parameter) - - extractPoints( divisions ) { - - return { - - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) - - }; - - } - - copy( source ) { - - super.copy( source ); - - this.holes = []; - - for ( let i = 0, l = source.holes.length; i < l; i ++ ) { - - const hole = source.holes[ i ]; - - this.holes.push( hole.clone() ); - - } - - return this; - - } - - toJSON() { - - const data = super.toJSON(); - - data.uuid = this.uuid; - data.holes = []; - - for ( let i = 0, l = this.holes.length; i < l; i ++ ) { - - const hole = this.holes[ i ]; - data.holes.push( hole.toJSON() ); - - } - - return data; - - } - - fromJSON( json ) { - - super.fromJSON( json ); - - this.uuid = json.uuid; - this.holes = []; - - for ( let i = 0, l = json.holes.length; i < l; i ++ ) { - - const hole = json.holes[ i ]; - this.holes.push( new Path().fromJSON( hole ) ); - - } - - return this; - - } - - } - - class Light extends Object3D { - - constructor( color, intensity = 1 ) { - - super(); - - this.type = 'Light'; - - this.color = new Color( color ); - this.intensity = intensity; - - } - - dispose() { - - // Empty here in base class; some subclasses override. - - } - - copy( source ) { - - super.copy( source ); - - this.color.copy( source.color ); - this.intensity = source.intensity; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; - - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); - - 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 data; - - } - - } - - Light.prototype.isLight = true; - - class HemisphereLight extends Light { - - constructor( skyColor, groundColor, intensity ) { - - super( skyColor, intensity ); - - this.type = 'HemisphereLight'; - - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); - - this.groundColor = new Color( groundColor ); - - } - - copy( source ) { - - Light.prototype.copy.call( this, source ); - - this.groundColor.copy( source.groundColor ); - - return this; - - } - - } - - HemisphereLight.prototype.isHemisphereLight = true; - - const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); - const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); - const _lookTarget$1 = /*@__PURE__*/ new Vector3(); - - class LightShadow { - - constructor( camera ) { - - this.camera = camera; - - this.bias = 0; - this.normalBias = 0; - this.radius = 1; - this.blurSamples = 8; - - this.mapSize = new Vector2( 512, 512 ); - - this.map = null; - this.mapPass = null; - this.matrix = new Matrix4(); - - this.autoUpdate = true; - this.needsUpdate = false; - - this._frustum = new Frustum(); - this._frameExtents = new Vector2( 1, 1 ); - - this._viewportCount = 1; - - this._viewports = [ - - new Vector4( 0, 0, 1, 1 ) - - ]; - - } - - getViewportCount() { - - return this._viewportCount; - - } - - getFrustum() { - - return this._frustum; - - } - - updateMatrices( light ) { - - const shadowCamera = this.camera; - const shadowMatrix = this.matrix; - - _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld$1 ); - - _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget$1 ); - shadowCamera.updateMatrixWorld(); - - _projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); - - shadowMatrix.set( - 0.5, 0.0, 0.0, 0.5, - 0.0, 0.5, 0.0, 0.5, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0 - ); - - shadowMatrix.multiply( shadowCamera.projectionMatrix ); - shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); - - } - - getViewport( viewportIndex ) { - - return this._viewports[ viewportIndex ]; - - } - - getFrameExtents() { - - return this._frameExtents; - - } - - dispose() { - - if ( this.map ) { - - this.map.dispose(); - - } - - if ( this.mapPass ) { - - this.mapPass.dispose(); - - } - - } - - copy( source ) { - - this.camera = source.camera.clone(); - - this.bias = source.bias; - this.radius = source.radius; - - this.mapSize.copy( source.mapSize ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - toJSON() { - - const object = {}; - - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); - - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; - - return object; - - } - - } - - class SpotLightShadow extends LightShadow { - - constructor() { - - super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - - this.focus = 1; - - } - - updateMatrices( light ) { - - const camera = this.camera; - - const fov = RAD2DEG * 2 * light.angle * this.focus; - const aspect = this.mapSize.width / this.mapSize.height; - const 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(); - - } - - super.updateMatrices( light ); - - } - - copy( source ) { - - super.copy( source ); - - this.focus = source.focus; - - return this; - - } - - } - - SpotLightShadow.prototype.isSpotLightShadow = true; - - class SpotLight extends Light { - - constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 1 ) { - - super( color, intensity ); - - this.type = 'SpotLight'; - - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); - - this.target = new Object3D(); - - this.distance = distance; - this.angle = angle; - this.penumbra = penumbra; - this.decay = decay; // for physically correct lights, should be 2. - - this.shadow = new SpotLightShadow(); - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in candela) - // by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd) - return this.intensity * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / Math.PI; - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source ) { - - super.copy( 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; - - } - - } - - SpotLight.prototype.isSpotLight = true; - - const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); - const _lightPositionWorld = /*@__PURE__*/ new Vector3(); - const _lookTarget = /*@__PURE__*/ new Vector3(); - - class PointLightShadow extends LightShadow { - - constructor() { - - super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - - this._frameExtents = new Vector2( 4, 2 ); - - this._viewportCount = 6; - - this._viewports = [ - // These viewports map a cube-map onto a 2D texture with the - // following orientation: - // - // xzXZ - // y Y - // - // X - Positive x direction - // x - Negative x direction - // Y - Positive y direction - // y - Negative y direction - // Z - Positive z direction - // z - Negative z direction - - // positive X - new Vector4( 2, 1, 1, 1 ), - // negative X - new Vector4( 0, 1, 1, 1 ), - // positive Z - new Vector4( 3, 1, 1, 1 ), - // negative Z - new Vector4( 1, 1, 1, 1 ), - // positive Y - new Vector4( 3, 0, 1, 1 ), - // negative Y - new Vector4( 1, 0, 1, 1 ) - ]; - - this._cubeDirections = [ - new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), - new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) - ]; - - this._cubeUps = [ - new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), - new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) - ]; - - } - - updateMatrices( light, viewportIndex = 0 ) { - - const camera = this.camera; - const shadowMatrix = this.matrix; - - const far = light.distance || camera.far; - - if ( far !== camera.far ) { - - camera.far = far; - camera.updateProjectionMatrix(); - - } - - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - camera.position.copy( _lightPositionWorld ); - - _lookTarget.copy( camera.position ); - _lookTarget.add( this._cubeDirections[ viewportIndex ] ); - camera.up.copy( this._cubeUps[ viewportIndex ] ); - camera.lookAt( _lookTarget ); - camera.updateMatrixWorld(); - - shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); - - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - this._frustum.setFromProjectionMatrix( _projScreenMatrix ); - - } - - } - - PointLightShadow.prototype.isPointLightShadow = true; - - class PointLight extends Light { - - constructor( color, intensity, distance = 0, decay = 1 ) { - - super( color, intensity ); - - this.type = 'PointLight'; - - this.distance = distance; - this.decay = decay; // for physically correct lights, should be 2. - - this.shadow = new PointLightShadow(); - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in candela) - // for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd) - return this.intensity * 4 * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in candela) from the desired luminous power (in lumens) - this.intensity = power / ( 4 * Math.PI ); - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source ) { - - super.copy( source ); - - this.distance = source.distance; - this.decay = source.decay; - - this.shadow = source.shadow.clone(); - - return this; - - } - - } - - PointLight.prototype.isPointLight = true; - - class DirectionalLightShadow extends LightShadow { - - constructor() { - - super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - - } - - } - - DirectionalLightShadow.prototype.isDirectionalLightShadow = true; - - class DirectionalLight extends Light { - - constructor( color, intensity ) { - - super( color, intensity ); - - this.type = 'DirectionalLight'; - - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); - - this.target = new Object3D(); - - this.shadow = new DirectionalLightShadow(); - - } - - dispose() { - - this.shadow.dispose(); - - } - - copy( source ) { - - super.copy( source ); - - this.target = source.target.clone(); - this.shadow = source.shadow.clone(); - - return this; - - } - - } - - DirectionalLight.prototype.isDirectionalLight = true; - - class AmbientLight extends Light { - - constructor( color, intensity ) { - - super( color, intensity ); - - this.type = 'AmbientLight'; - - } - - } - - AmbientLight.prototype.isAmbientLight = true; - - class RectAreaLight extends Light { - - constructor( color, intensity, width = 10, height = 10 ) { - - super( color, intensity ); - - this.type = 'RectAreaLight'; - - this.width = width; - this.height = height; - - } - - get power() { - - // compute the light's luminous power (in lumens) from its intensity (in nits) - return this.intensity * this.width * this.height * Math.PI; - - } - - set power( power ) { - - // set the light's intensity (in nits) from the desired luminous power (in lumens) - this.intensity = power / ( this.width * this.height * Math.PI ); - - } - - copy( source ) { - - super.copy( source ); - - this.width = source.width; - this.height = source.height; - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.width = this.width; - data.object.height = this.height; - - return data; - - } - - } - - RectAreaLight.prototype.isRectAreaLight = true; - - /** - * Primary reference: - * https://graphics.stanford.edu/papers/envmap/envmap.pdf - * - * Secondary reference: - * https://www.ppsloan.org/publications/StupidSH36.pdf - */ - - // 3-band SH defined by 9 coefficients - - class SphericalHarmonics3 { - - constructor() { - - this.coefficients = []; - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients.push( new Vector3() ); - - } - - } - - set( coefficients ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].copy( coefficients[ i ] ); - - } - - return this; - - } - - zero() { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].set( 0, 0, 0 ); - - } - - return this; - - } - - // get the radiance in the direction of the normal - // target is a Vector3 - getAt( normal, target ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - const coeff = this.coefficients; - - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); - - // band 1 - target.addScaledVector( coeff[ 1 ], 0.488603 * y ); - target.addScaledVector( coeff[ 2 ], 0.488603 * z ); - target.addScaledVector( coeff[ 3 ], 0.488603 * x ); - - // band 2 - target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); - target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); - target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); - target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); - target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); - - return target; - - } - - // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal - // target is a Vector3 - // https://graphics.stanford.edu/papers/envmap/envmap.pdf - getIrradianceAt( normal, target ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - const coeff = this.coefficients; - - // band 0 - target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 - - // band 1 - target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603 - target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); - target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); - - // band 2 - target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548 - target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); - target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3 - target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); - target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274 - - return target; - - } - - add( sh ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].add( sh.coefficients[ i ] ); - - } - - return this; - - } - - addScaledSH( sh, s ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); - - } - - return this; - - } - - scale( s ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].multiplyScalar( s ); - - } - - return this; - - } - - lerp( sh, alpha ) { - - for ( let i = 0; i < 9; i ++ ) { - - this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); - - } - - return this; - - } - - equals( sh ) { - - for ( let i = 0; i < 9; i ++ ) { - - if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { - - return false; - - } - - } - - return true; - - } - - copy( sh ) { - - return this.set( sh.coefficients ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - fromArray( array, offset = 0 ) { - - const coefficients = this.coefficients; - - for ( let i = 0; i < 9; i ++ ) { - - coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); - - } - - return this; - - } - - toArray( array = [], offset = 0 ) { - - const coefficients = this.coefficients; - - for ( let i = 0; i < 9; i ++ ) { - - coefficients[ i ].toArray( array, offset + ( i * 3 ) ); - - } - - return array; - - } - - // evaluate the basis functions - // shBasis is an Array[ 9 ] - static getBasisAt( normal, shBasis ) { - - // normal is assumed to be unit length - - const x = normal.x, y = normal.y, z = normal.z; - - // band 0 - shBasis[ 0 ] = 0.282095; - - // band 1 - shBasis[ 1 ] = 0.488603 * y; - shBasis[ 2 ] = 0.488603 * z; - shBasis[ 3 ] = 0.488603 * x; - - // band 2 - shBasis[ 4 ] = 1.092548 * x * y; - shBasis[ 5 ] = 1.092548 * y * z; - shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); - shBasis[ 7 ] = 1.092548 * x * z; - shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); - - } - - } - - SphericalHarmonics3.prototype.isSphericalHarmonics3 = true; - - class LightProbe extends Light { - - constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { - - super( undefined, intensity ); - - this.sh = sh; - - } - - copy( source ) { - - super.copy( source ); - - this.sh.copy( source.sh ); - - return this; - - } - - fromJSON( json ) { - - this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); - this.sh.fromArray( json.sh ); - - return this; - - } - - toJSON( meta ) { - - const data = super.toJSON( meta ); - - data.object.sh = this.sh.toArray(); - - return data; - - } - - } - - LightProbe.prototype.isLightProbe = true; - - class MaterialLoader extends Loader { - - constructor( manager ) { - - super( manager ); - this.textures = {}; - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const textures = this.textures; - - function getTexture( name ) { - - if ( textures[ name ] === undefined ) { - - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); - - } - - return textures[ name ]; - - } - - const 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 !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.sheenTint !== undefined ) material.sheenTint = new Color().setHex( json.sheenTint ); - if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; - if ( json.specularTint !== undefined && material.specularTint !== undefined ) material.specularTint.setHex( json.specularTint ); - 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.transmission !== undefined ) material.transmission = json.transmission; - if ( json.thickness !== undefined ) material.thickness = json.thickness; - if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; - if ( json.attenuationTint !== undefined && material.attenuationTint !== undefined ) material.attenuationTint.setHex( json.attenuationTint ); - 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.combine !== undefined ) material.combine = json.combine; - if ( json.side !== undefined ) material.side = json.side; - if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.format !== undefined ) material.format = json.format; - 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.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; - if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; - if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; - if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; - if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; - if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; - if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; - if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; - - 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; - - if ( json.rotation !== undefined ) material.rotation = json.rotation; - - 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; - - if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; - if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; - if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; - - if ( json.dithering !== undefined ) material.dithering = json.dithering; - - if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; - if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; - - if ( json.visible !== undefined ) material.visible = json.visible; - - if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; - - if ( json.userData !== undefined ) material.userData = json.userData; - - if ( json.vertexColors !== undefined ) { - - if ( typeof json.vertexColors === 'number' ) { - - material.vertexColors = ( json.vertexColors > 0 ) ? true : false; - - } else { - - material.vertexColors = json.vertexColors; - - } - - } - - // Shader Material - - if ( json.uniforms !== undefined ) { - - for ( const name in json.uniforms ) { - - const uniform = json.uniforms[ name ]; - - material.uniforms[ name ] = {}; - - switch ( uniform.type ) { - - case 't': - material.uniforms[ name ].value = getTexture( uniform.value ); - break; - - case 'c': - material.uniforms[ name ].value = new Color().setHex( uniform.value ); - break; - - case 'v2': - material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); - break; - - case 'v3': - material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); - break; - - case 'v4': - material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); - break; - - case 'm3': - material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); - break; - - case 'm4': - material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); - break; - - default: - material.uniforms[ name ].value = uniform.value; - - } - - } - - } - - if ( json.defines !== undefined ) material.defines = json.defines; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; - - if ( json.extensions !== undefined ) { - - for ( const key in json.extensions ) { - - material.extensions[ key ] = json.extensions[ key ]; - - } - - } - - // Deprecated - - if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading - - // for PointsMaterial - - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; - - // maps - - if ( json.map !== undefined ) material.map = getTexture( json.map ); - if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); - - if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); - - 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.normalMapType !== undefined ) material.normalMapType = json.normalMapType; - if ( json.normalScale !== undefined ) { - - let normalScale = json.normalScale; - - if ( Array.isArray( normalScale ) === false ) { - - // Blender exporter used to export a scalar. See #7459 - - normalScale = [ normalScale, normalScale ]; - - } - - material.normalScale = new Vector2().fromArray( normalScale ); - - } - - 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; - - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); - if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); - if ( json.specularTintMap !== undefined ) material.specularTintMap = getTexture( json.specularTintMap ); - - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; - - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; - if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; - - if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); - if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; - - 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 ); - - if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); - if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); - if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); - if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); - - if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); - if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); - - return material; - - } - - setTextures( value ) { - - this.textures = value; - return this; - - } - - } - - class LoaderUtils { - - static decodeText( array ) { - - if ( typeof TextDecoder !== 'undefined' ) { - - return new TextDecoder().decode( array ); - - } - - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. - - let s = ''; - - for ( let i = 0, il = array.length; i < il; i ++ ) { - - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); - - } - - try { - - // merges multi-byte utf-8 characters. - - return decodeURIComponent( escape( s ) ); - - } catch ( e ) { // see #16358 - - return s; - - } - - } - - static extractUrlBase( url ) { - - const index = url.lastIndexOf( '/' ); - - if ( index === - 1 ) return './'; - - return url.substr( 0, index + 1 ); - - } - - } - - class InstancedBufferGeometry extends BufferGeometry { - - constructor() { - - super(); - - this.type = 'InstancedBufferGeometry'; - this.instanceCount = Infinity; - - } - - copy( source ) { - - super.copy( source ); - - this.instanceCount = source.instanceCount; - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - toJSON() { - - const data = super.toJSON( this ); - - data.instanceCount = this.instanceCount; - - data.isInstancedBufferGeometry = true; - - return data; - - } - - } - - InstancedBufferGeometry.prototype.isInstancedBufferGeometry = true; - - class BufferGeometryLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.setRequestHeader( scope.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { - - try { - - onLoad( scope.parse( JSON.parse( text ) ) ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - parse( json ) { - - const interleavedBufferMap = {}; - const arrayBufferMap = {}; - - function getInterleavedBuffer( json, uuid ) { - - if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; - - const interleavedBuffers = json.interleavedBuffers; - const interleavedBuffer = interleavedBuffers[ uuid ]; - - const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); - - const array = getTypedArray( interleavedBuffer.type, buffer ); - const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); - ib.uuid = interleavedBuffer.uuid; - - interleavedBufferMap[ uuid ] = ib; - - return ib; - - } - - function getArrayBuffer( json, uuid ) { - - if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; - - const arrayBuffers = json.arrayBuffers; - const arrayBuffer = arrayBuffers[ uuid ]; - - const ab = new Uint32Array( arrayBuffer ).buffer; - - arrayBufferMap[ uuid ] = ab; - - return ab; - - } - - const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); - - const index = json.data.index; - - if ( index !== undefined ) { - - const typedArray = getTypedArray( index.type, index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); - - } - - const attributes = json.data.attributes; - - for ( const key in attributes ) { - - const attribute = attributes[ key ]; - let bufferAttribute; - - if ( attribute.isInterleavedBufferAttribute ) { - - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - - } else { - - const typedArray = getTypedArray( attribute.type, attribute.array ); - const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; - bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); - - } - - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); - - if ( attribute.updateRange !== undefined ) { - - bufferAttribute.updateRange.offset = attribute.updateRange.offset; - bufferAttribute.updateRange.count = attribute.updateRange.count; - - } - - geometry.setAttribute( key, bufferAttribute ); - - } - - const morphAttributes = json.data.morphAttributes; - - if ( morphAttributes ) { - - for ( const key in morphAttributes ) { - - const attributeArray = morphAttributes[ key ]; - - const array = []; - - for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { - - const attribute = attributeArray[ i ]; - let bufferAttribute; - - if ( attribute.isInterleavedBufferAttribute ) { - - const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); - bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - - } else { - - const typedArray = getTypedArray( attribute.type, attribute.array ); - bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); - - } - - if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; - array.push( bufferAttribute ); - - } - - geometry.morphAttributes[ key ] = array; - - } - - } - - const morphTargetsRelative = json.data.morphTargetsRelative; - - if ( morphTargetsRelative ) { - - geometry.morphTargetsRelative = true; - - } - - const groups = json.data.groups || json.data.drawcalls || json.data.offsets; - - if ( groups !== undefined ) { - - for ( let i = 0, n = groups.length; i !== n; ++ i ) { - - const group = groups[ i ]; - - geometry.addGroup( group.start, group.count, group.materialIndex ); - - } - - } - - const boundingSphere = json.data.boundingSphere; - - if ( boundingSphere !== undefined ) { - - const center = new Vector3(); - - if ( boundingSphere.center !== undefined ) { - - center.fromArray( boundingSphere.center ); - - } - - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - - } - - if ( json.name ) geometry.name = json.name; - if ( json.userData ) geometry.userData = json.userData; - - return geometry; - - } - - } - - class ObjectLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { - - let json = null; - - try { - - json = JSON.parse( text ); - - } catch ( error ) { - - if ( onError !== undefined ) onError( error ); - - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - - return; - - } - - const metadata = json.metadata; - - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - - console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); - return; - - } - - scope.parse( json, onLoad ); - - }, onProgress, onError ); - - } - - async loadAsync( url, onProgress ) { - - const scope = this; - - const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - - const text = await loader.loadAsync( url, onProgress ); - - const json = JSON.parse( text ); - - const metadata = json.metadata; - - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - - throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); - - } - - return await scope.parseAsync( json ); - - } - - parse( json, onLoad ) { - - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); - - const images = this.parseImages( json.images, function () { - - if ( onLoad !== undefined ) onLoad( object ); - - } ); - - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); - - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); - - this.bindSkeletons( object, skeletons ); - - // - - if ( onLoad !== undefined ) { - - let hasImages = false; - - for ( const uuid in images ) { - - if ( images[ uuid ] instanceof HTMLImageElement ) { - - hasImages = true; - break; - - } - - } - - if ( hasImages === false ) onLoad( object ); - - } - - return object; - - } - - async parseAsync( json ) { - - const animations = this.parseAnimations( json.animations ); - const shapes = this.parseShapes( json.shapes ); - const geometries = this.parseGeometries( json.geometries, shapes ); - - const images = await this.parseImagesAsync( json.images ); - - const textures = this.parseTextures( json.textures, images ); - const materials = this.parseMaterials( json.materials, textures ); - - const object = this.parseObject( json.object, geometries, materials, textures, animations ); - const skeletons = this.parseSkeletons( json.skeletons, object ); - - this.bindSkeletons( object, skeletons ); - - return object; - - } - - parseShapes( json ) { - - const shapes = {}; - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const shape = new Shape().fromJSON( json[ i ] ); - - shapes[ shape.uuid ] = shape; - - } - - } - - return shapes; - - } - - parseSkeletons( json, object ) { - - const skeletons = {}; - const bones = {}; - - // generate bone lookup table - - object.traverse( function ( child ) { - - if ( child.isBone ) bones[ child.uuid ] = child; - - } ); - - // create skeletons - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const skeleton = new Skeleton().fromJSON( json[ i ], bones ); - - skeletons[ skeleton.uuid ] = skeleton; - - } - - } - - return skeletons; - - } - - parseGeometries( json, shapes ) { - - const geometries = {}; - - if ( json !== undefined ) { - - const bufferGeometryLoader = new BufferGeometryLoader(); - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - let geometry; - const data = json[ i ]; - - switch ( data.type ) { - - case 'BufferGeometry': - case 'InstancedBufferGeometry': - - geometry = bufferGeometryLoader.parse( data ); - - break; - - case 'Geometry': - - console.error( 'THREE.ObjectLoader: The legacy Geometry type is no longer supported.' ); - - break; - - default: - - if ( data.type in Geometries ) { - - geometry = Geometries[ data.type ].fromJSON( data, shapes ); - - } else { - - console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); - - } - - } - - geometry.uuid = data.uuid; - - if ( data.name !== undefined ) geometry.name = data.name; - if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData; - - geometries[ data.uuid ] = geometry; - - } - - } - - return geometries; - - } - - parseMaterials( json, textures ) { - - const cache = {}; // MultiMaterial - const materials = {}; - - if ( json !== undefined ) { - - const loader = new MaterialLoader(); - loader.setTextures( textures ); - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const data = json[ i ]; - - if ( data.type === 'MultiMaterial' ) { - - // Deprecated - - const array = []; - - for ( let j = 0; j < data.materials.length; j ++ ) { - - const material = data.materials[ j ]; - - if ( cache[ material.uuid ] === undefined ) { - - cache[ material.uuid ] = loader.parse( material ); - - } - - array.push( cache[ material.uuid ] ); - - } - - materials[ data.uuid ] = array; - - } else { - - if ( cache[ data.uuid ] === undefined ) { - - cache[ data.uuid ] = loader.parse( data ); - - } - - materials[ data.uuid ] = cache[ data.uuid ]; - - } - - } - - } - - return materials; - - } - - parseAnimations( json ) { - - const animations = {}; - - if ( json !== undefined ) { - - for ( let i = 0; i < json.length; i ++ ) { - - const data = json[ i ]; - - const clip = AnimationClip.parse( data ); - - animations[ clip.uuid ] = clip; - - } - - } - - return animations; - - } - - parseImages( json, onLoad ) { - - const scope = this; - const images = {}; - - let loader; - - function loadImage( url ) { - - scope.manager.itemStart( url ); - - return loader.load( url, function () { - - scope.manager.itemEnd( url ); - - }, undefined, function () { - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } ); - - } - - function deserializeImage( image ) { - - if ( typeof image === 'string' ) { - - const url = image; - - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - - return loadImage( path ); - - } else { - - if ( image.data ) { - - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; - - } else { - - return null; - - } - - } - - } - - if ( json !== undefined && json.length > 0 ) { - - const manager = new LoadingManager( onLoad ); - - loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); - - for ( let i = 0, il = json.length; i < il; i ++ ) { - - const image = json[ i ]; - const url = image.url; - - if ( Array.isArray( url ) ) { - - // load array of images e.g CubeTexture - - images[ image.uuid ] = []; - - for ( let j = 0, jl = url.length; j < jl; j ++ ) { - - const currentUrl = url[ j ]; - - const deserializedImage = deserializeImage( currentUrl ); - - if ( deserializedImage !== null ) { - - if ( deserializedImage instanceof HTMLImageElement ) { - - images[ image.uuid ].push( deserializedImage ); - - } else { - - // special case: handle array of data textures for cube textures - - images[ image.uuid ].push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - - } - - } - - } - - } else { - - // load single image - - const deserializedImage = deserializeImage( image.url ); - - if ( deserializedImage !== null ) { - - images[ image.uuid ] = deserializedImage; - - } - - } - - } - - } - - return images; - - } - - async parseImagesAsync( json ) { - - const scope = this; - const images = {}; - - let loader; - - async function deserializeImage( image ) { - - if ( typeof image === 'string' ) { - - const url = image; - - const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; - - return await loader.loadAsync( path ); - - } else { - - if ( image.data ) { - - return { - data: getTypedArray( image.type, image.data ), - width: image.width, - height: image.height - }; - - } else { - - return null; - - } - - } - - } - - if ( json !== undefined && json.length > 0 ) { - - loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - - for ( let i = 0, il = json.length; i < il; i ++ ) { - - const image = json[ i ]; - const url = image.url; - - if ( Array.isArray( url ) ) { - - // load array of images e.g CubeTexture - - images[ image.uuid ] = []; - - for ( let j = 0, jl = url.length; j < jl; j ++ ) { - - const currentUrl = url[ j ]; - - const deserializedImage = await deserializeImage( currentUrl ); - - if ( deserializedImage !== null ) { - - if ( deserializedImage instanceof HTMLImageElement ) { - - images[ image.uuid ].push( deserializedImage ); - - } else { - - // special case: handle array of data textures for cube textures - - images[ image.uuid ].push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); - - } - - } - - } - - } else { - - // load single image - - const deserializedImage = await deserializeImage( image.url ); - - if ( deserializedImage !== null ) { - - images[ image.uuid ] = deserializedImage; - - } - - } - - } - - } - - return images; - - } - - parseTextures( json, images ) { - - function parseConstant( value, type ) { - - if ( typeof value === 'number' ) return value; - - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); - - return type[ value ]; - - } - - const textures = {}; - - if ( json !== undefined ) { - - for ( let i = 0, l = json.length; i < l; i ++ ) { - - const data = json[ i ]; - - if ( data.image === undefined ) { - - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - - } - - if ( images[ data.image ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - - } - - let texture; - const image = images[ data.image ]; - - if ( Array.isArray( image ) ) { - - texture = new CubeTexture( image ); - - if ( image.length === 6 ) texture.needsUpdate = true; - - } else { - - if ( image && image.data ) { - - texture = new DataTexture( image.data, image.width, image.height ); - - } else { - - texture = new Texture( image ); - - } - - if ( image ) texture.needsUpdate = true; // textures can have undefined image data - - } - - texture.uuid = data.uuid; - - if ( data.name !== undefined ) texture.name = data.name; - - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); - - 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; - - if ( data.wrap !== undefined ) { - - texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); - texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - - } - - if ( data.format !== undefined ) texture.format = data.format; - if ( data.type !== undefined ) texture.type = data.type; - if ( data.encoding !== undefined ) texture.encoding = data.encoding; - - 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; - - if ( data.flipY !== undefined ) texture.flipY = data.flipY; - - if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; - if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; - - textures[ data.uuid ] = texture; - - } - - } - - return textures; - - } - - parseObject( data, geometries, materials, textures, animations ) { - - let object; - - function getGeometry( name ) { - - if ( geometries[ name ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - - } - - return geometries[ name ]; - - } - - function getMaterial( name ) { - - if ( name === undefined ) return undefined; - - if ( Array.isArray( name ) ) { - - const array = []; - - for ( let i = 0, l = name.length; i < l; i ++ ) { - - const uuid = name[ i ]; - - if ( materials[ uuid ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); - - } - - array.push( materials[ uuid ] ); - - } - - return array; - - } - - if ( materials[ name ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined material', name ); - - } - - return materials[ name ]; - - } - - function getTexture( uuid ) { - - if ( textures[ uuid ] === undefined ) { - - console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); - - } - - return textures[ uuid ]; - - } - - let geometry, material; - - switch ( data.type ) { - - case 'Scene': - - object = new Scene(); - - if ( data.background !== undefined ) { - - if ( Number.isInteger( data.background ) ) { - - object.background = new Color( data.background ); - - } else { - - object.background = getTexture( data.background ); - - } - - } - - if ( data.environment !== undefined ) { - - object.environment = getTexture( data.environment ); - - } - - if ( data.fog !== undefined ) { - - if ( data.fog.type === 'Fog' ) { - - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - - } else if ( data.fog.type === 'FogExp2' ) { - - object.fog = new FogExp2( data.fog.color, data.fog.density ); - - } - - } - - break; - - case 'PerspectiveCamera': - - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); - - 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; - - case 'OrthographicCamera': - - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); - - break; - - case 'AmbientLight': - - object = new AmbientLight( data.color, data.intensity ); - - break; - - case 'DirectionalLight': - - object = new DirectionalLight( data.color, data.intensity ); - - break; - - case 'PointLight': - - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - - break; - - case 'RectAreaLight': - - 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 ); - - break; - - case 'HemisphereLight': - - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - - break; - - case 'LightProbe': - - object = new LightProbe().fromJSON( data ); - - break; - - case 'SkinnedMesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - - object = new SkinnedMesh( geometry, material ); - - if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; - if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); - if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; - - break; - - case 'Mesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - - object = new Mesh( geometry, material ); - - break; - - case 'InstancedMesh': - - geometry = getGeometry( data.geometry ); - material = getMaterial( data.material ); - const count = data.count; - const instanceMatrix = data.instanceMatrix; - const instanceColor = data.instanceColor; - - object = new InstancedMesh( geometry, material, count ); - object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); - if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); - - break; - - case 'LOD': - - object = new LOD(); - - break; - - case 'Line': - - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'LineLoop': - - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'LineSegments': - - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'PointCloud': - case 'Points': - - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - - break; - - case 'Sprite': - - object = new Sprite( getMaterial( data.material ) ); - - break; - - case 'Group': - - object = new Group(); - - break; - - case 'Bone': - - object = new Bone(); - - break; - - default: - - object = new Object3D(); - - } - - object.uuid = data.uuid; - - if ( data.name !== undefined ) object.name = data.name; - - if ( data.matrix !== undefined ) { - - object.matrix.fromArray( data.matrix ); - - if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; - if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); - - } else { - - if ( data.position !== undefined ) object.position.fromArray( data.position ); - if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); - if ( data.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; - - if ( data.shadow ) { - - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; - 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 ); - - } - - if ( data.visible !== undefined ) object.visible = data.visible; - if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; - if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; - if ( data.userData !== undefined ) object.userData = data.userData; - if ( data.layers !== undefined ) object.layers.mask = data.layers; - - if ( data.children !== undefined ) { - - const children = data.children; - - for ( let i = 0; i < children.length; i ++ ) { - - object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); - - } - - } - - if ( data.animations !== undefined ) { - - const objectAnimations = data.animations; - - for ( let i = 0; i < objectAnimations.length; i ++ ) { - - const uuid = objectAnimations[ i ]; - - object.animations.push( animations[ uuid ] ); - - } - - } - - if ( data.type === 'LOD' ) { - - if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; - - const levels = data.levels; - - for ( let l = 0; l < levels.length; l ++ ) { - - const level = levels[ l ]; - const child = object.getObjectByProperty( 'uuid', level.object ); - - if ( child !== undefined ) { - - object.addLevel( child, level.distance ); - - } - - } - - } - - return object; - - } - - bindSkeletons( object, skeletons ) { - - if ( Object.keys( skeletons ).length === 0 ) return; - - object.traverse( function ( child ) { - - if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { - - const skeleton = skeletons[ child.skeleton ]; - - if ( skeleton === undefined ) { - - console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); - - } else { - - child.bind( skeleton, child.bindMatrix ); - - } - - } - - } ); - - } - - /* DEPRECATED */ - - setTexturePath( value ) { - - console.warn( 'THREE.ObjectLoader: .setTexturePath() has been renamed to .setResourcePath().' ); - return this.setResourcePath( value ); - - } - - } - - const TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubeUVRefractionMapping: CubeUVRefractionMapping - }; - - const TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping - }; - - const TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipmapNearestFilter: NearestMipmapNearestFilter, - NearestMipmapLinearFilter: NearestMipmapLinearFilter, - LinearFilter: LinearFilter, - LinearMipmapNearestFilter: LinearMipmapNearestFilter, - LinearMipmapLinearFilter: LinearMipmapLinearFilter - }; - - class ImageBitmapLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - if ( typeof createImageBitmap === 'undefined' ) { - - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - - } - - if ( typeof fetch === 'undefined' ) { - - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - - } - - this.options = { premultiplyAlpha: 'none' }; - - } - - setOptions( options ) { - - this.options = options; - - return this; - - } - - load( url, onLoad, onProgress, onError ) { - - if ( url === undefined ) url = ''; - - if ( this.path !== undefined ) url = this.path + url; - - url = this.manager.resolveURL( url ); - - const scope = this; - - const cached = Cache.get( url ); - - if ( cached !== undefined ) { - - scope.manager.itemStart( url ); - - setTimeout( function () { - - if ( onLoad ) onLoad( cached ); - - scope.manager.itemEnd( url ); - - }, 0 ); - - return cached; - - } - - const fetchOptions = {}; - fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; - fetchOptions.headers = this.requestHeader; - - fetch( url, fetchOptions ).then( function ( res ) { - - return res.blob(); - - } ).then( function ( blob ) { - - return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); - - } ).then( function ( imageBitmap ) { - - Cache.add( url, imageBitmap ); - - if ( onLoad ) onLoad( imageBitmap ); - - scope.manager.itemEnd( url ); - - } ).catch( function ( e ) { - - if ( onError ) onError( e ); - - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); - - } ); - - scope.manager.itemStart( url ); - - } - - } - - ImageBitmapLoader.prototype.isImageBitmapLoader = true; - - class ShapePath { - - constructor() { - - this.type = 'ShapePath'; - - this.color = new Color(); - - this.subPaths = []; - this.currentPath = null; - - } - - moveTo( x, y ) { - - this.currentPath = new Path(); - this.subPaths.push( this.currentPath ); - this.currentPath.moveTo( x, y ); - - return this; - - } - - lineTo( x, y ) { - - this.currentPath.lineTo( x, y ); - - return this; - - } - - quadraticCurveTo( aCPx, aCPy, aX, aY ) { - - this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); - - return this; - - } - - bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); - - return this; - - } - - splineThru( pts ) { - - this.currentPath.splineThru( pts ); - - return this; - - } - - toShapes( isCCW, noHoles ) { - - function toShapesNoHoles( inSubpaths ) { - - const shapes = []; - - for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { - - const tmpPath = inSubpaths[ i ]; - - const tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - - shapes.push( tmpShape ); - - } - - return shapes; - - } - - function isPointInsidePolygon( inPt, inPolygon ) { - - const polyLen = inPolygon.length; - - // inPt on polygon contour => immediate success or - // toggling of inside/outside at every single! intersection point of an edge - // with the horizontal line through inPt, left of inPt - // not counting lowerY endpoints of edges and whole edges on that line - let inside = false; - for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { - - let edgeLowPt = inPolygon[ p ]; - let edgeHighPt = inPolygon[ q ]; - - let edgeDx = edgeHighPt.x - edgeLowPt.x; - let edgeDy = edgeHighPt.y - edgeLowPt.y; - - if ( Math.abs( edgeDy ) > Number.EPSILON ) { - - // not parallel - if ( edgeDy < 0 ) { - - edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; - - } - - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; - - if ( inPt.y === edgeLowPt.y ) { - - if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! - - } else { - - const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); - if ( perpEdge === 0 ) return true; // inPt is on contour ? - if ( perpEdge < 0 ) continue; - inside = ! inside; // true intersection left of inPt - - } - - } else { - - // parallel or collinear - if ( inPt.y !== edgeLowPt.y ) continue; // parallel - // edge lies on the same horizontal line as inPt - if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || - ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! - // continue; - - } - - } - - return inside; - - } - - const isClockWise = ShapeUtils.isClockWise; - - const subPaths = this.subPaths; - if ( subPaths.length === 0 ) return []; - - if ( noHoles === true ) return toShapesNoHoles( subPaths ); - - - let solid, tmpPath, tmpShape; - const shapes = []; - - if ( subPaths.length === 1 ) { - - tmpPath = subPaths[ 0 ]; - tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; - - } - - let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? ! holesFirst : holesFirst; - - // console.log("Holes first", holesFirst); - - const betterShapeHoles = []; - const newShapes = []; - let newShapeHoles = []; - let mainIdx = 0; - let tmpPoints; - - newShapes[ mainIdx ] = undefined; - newShapeHoles[ mainIdx ] = []; - - for ( let i = 0, l = subPaths.length; i < l; i ++ ) { - - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; - - if ( solid ) { - - if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; - - newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; - newShapes[ mainIdx ].s.curves = tmpPath.curves; - - if ( holesFirst ) mainIdx ++; - newShapeHoles[ mainIdx ] = []; - - //console.log('cw', i); - - } else { - - newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); - - //console.log('ccw', i); - - } - - } - - // only Holes? -> probably all Shapes with wrong orientation - if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); - - - if ( newShapes.length > 1 ) { - - let ambiguous = false; - const toChange = []; - - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - betterShapeHoles[ sIdx ] = []; - - } - - for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - - const sho = newShapeHoles[ sIdx ]; - - for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { - - const ho = sho[ hIdx ]; - let hole_unassigned = true; - - for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { - - if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { - - if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); - if ( hole_unassigned ) { - - hole_unassigned = false; - betterShapeHoles[ s2Idx ].push( ho ); - - } else { - - ambiguous = true; - - } - - } - - } - - if ( hole_unassigned ) { - - betterShapeHoles[ sIdx ].push( ho ); - - } - - } - - } - // console.log("ambiguous: ", ambiguous); - - if ( toChange.length > 0 ) { - - // console.log("to change: ", toChange); - if ( ! ambiguous ) newShapeHoles = betterShapeHoles; - - } - - } - - let tmpHoles; - - for ( let i = 0, il = newShapes.length; i < il; i ++ ) { - - tmpShape = newShapes[ i ].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[ i ]; - - for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - - tmpShape.holes.push( tmpHoles[ j ].h ); - - } - - } - - //console.log("shape", shapes); - - return shapes; - - } - - } - - class Font { - - constructor( data ) { - - this.type = 'Font'; - - this.data = data; - - } - - generateShapes( text, size = 100 ) { - - const shapes = []; - const paths = createPaths( text, size, this.data ); - - for ( let p = 0, pl = paths.length; p < pl; p ++ ) { - - Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); - - } - - return shapes; - - } - - } - - function createPaths( text, size, data ) { - - const chars = Array.from( text ); - const scale = size / data.resolution; - const line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale; - - const paths = []; - - let offsetX = 0, offsetY = 0; - - for ( let i = 0; i < chars.length; i ++ ) { - - const char = chars[ i ]; - - if ( char === '\n' ) { - - offsetX = 0; - offsetY -= line_height; - - } else { - - const ret = createPath( char, scale, offsetX, offsetY, data ); - offsetX += ret.offsetX; - paths.push( ret.path ); - - } - - } - - return paths; - - } - - function createPath( char, scale, offsetX, offsetY, data ) { - - const glyph = data.glyphs[ char ] || data.glyphs[ '?' ]; - - if ( ! glyph ) { - - console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' ); - - return; - - } - - const path = new ShapePath(); - - let x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2; - - if ( glyph.o ) { - - const outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); - - for ( let i = 0, l = outline.length; i < l; ) { - - const action = outline[ i ++ ]; - - switch ( action ) { - - case 'm': // moveTo - - x = outline[ i ++ ] * scale + offsetX; - y = outline[ i ++ ] * scale + offsetY; - - path.moveTo( x, y ); - - break; - - case 'l': // lineTo - - x = outline[ i ++ ] * scale + offsetX; - y = outline[ i ++ ] * scale + offsetY; - - path.lineTo( x, y ); - - break; - - case 'q': // quadraticCurveTo - - cpx = outline[ i ++ ] * scale + offsetX; - cpy = outline[ i ++ ] * scale + offsetY; - cpx1 = outline[ i ++ ] * scale + offsetX; - cpy1 = outline[ i ++ ] * scale + offsetY; - - path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); - - break; - - case 'b': // bezierCurveTo - - cpx = outline[ i ++ ] * scale + offsetX; - cpy = outline[ i ++ ] * scale + offsetY; - cpx1 = outline[ i ++ ] * scale + offsetX; - cpy1 = outline[ i ++ ] * scale + offsetY; - cpx2 = outline[ i ++ ] * scale + offsetX; - cpy2 = outline[ i ++ ] * scale + offsetY; - - path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); - - break; - - } - - } - - } - - return { offsetX: glyph.ha * scale, path: path }; - - } - - Font.prototype.isFont = true; - - class FontLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( scope.withCredentials ); - loader.load( url, function ( text ) { - - let json; - - try { - - json = JSON.parse( text ); - - } catch ( e ) { - - console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' ); - json = JSON.parse( text.substring( 65, text.length - 2 ) ); - - } - - const font = scope.parse( json ); - - if ( onLoad ) onLoad( font ); - - }, onProgress, onError ); - - } - - parse( json ) { - - return new Font( json ); - - } - - } - - let _context; - - const AudioContext = { - - getContext: function () { - - if ( _context === undefined ) { - - _context = new ( window.AudioContext || window.webkitAudioContext )(); - - } - - return _context; - - }, - - setContext: function ( value ) { - - _context = value; - - } - - }; - - class AudioLoader extends Loader { - - constructor( manager ) { - - super( manager ); - - } - - load( url, onLoad, onProgress, onError ) { - - const scope = this; - - const loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setPath( this.path ); - loader.setRequestHeader( this.requestHeader ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( buffer ) { - - try { - - // Create a copy of the buffer. The `decodeAudioData` method - // detaches the buffer when complete, preventing reuse. - const bufferCopy = buffer.slice( 0 ); - - const context = AudioContext.getContext(); - context.decodeAudioData( bufferCopy, function ( audioBuffer ) { - - onLoad( audioBuffer ); - - } ); - - } catch ( e ) { - - if ( onError ) { - - onError( e ); - - } else { - - console.error( e ); - - } - - scope.manager.itemError( url ); - - } - - }, onProgress, onError ); - - } - - } - - class HemisphereLightProbe extends LightProbe { - - constructor( skyColor, groundColor, intensity = 1 ) { - - super( undefined, intensity ); - - const color1 = new Color().set( skyColor ); - const color2 = new Color().set( groundColor ); - - const sky = new Vector3( color1.r, color1.g, color1.b ); - const ground = new Vector3( color2.r, color2.g, color2.b ); - - // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI ); - const c0 = Math.sqrt( Math.PI ); - const c1 = c0 * Math.sqrt( 0.75 ); - - this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 ); - this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 ); - - } - - } - - HemisphereLightProbe.prototype.isHemisphereLightProbe = true; - - class AmbientLightProbe extends LightProbe { - - constructor( color, intensity = 1 ) { - - super( undefined, intensity ); - - const color1 = new Color().set( color ); - - // without extra factor of PI in the shader, would be 2 / Math.sqrt( Math.PI ); - this.sh.coefficients[ 0 ].set( color1.r, color1.g, color1.b ).multiplyScalar( 2 * Math.sqrt( Math.PI ) ); - - } - - } - - AmbientLightProbe.prototype.isAmbientLightProbe = true; - - const _eyeRight = /*@__PURE__*/ new Matrix4(); - const _eyeLeft = /*@__PURE__*/ new Matrix4(); - - class StereoCamera { - - constructor() { - - this.type = 'StereoCamera'; - - this.aspect = 1; - - this.eyeSep = 0.064; - - this.cameraL = new PerspectiveCamera(); - this.cameraL.layers.enable( 1 ); - this.cameraL.matrixAutoUpdate = false; - - this.cameraR = new PerspectiveCamera(); - this.cameraR.layers.enable( 2 ); - this.cameraR.matrixAutoUpdate = false; - - this._cache = { - focus: null, - fov: null, - aspect: null, - near: null, - far: null, - zoom: null, - eyeSep: null - }; - - } - - update( camera ) { - - const cache = this._cache; - - const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || - cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || - cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; - - if ( needsUpdate ) { - - cache.focus = camera.focus; - cache.fov = camera.fov; - cache.aspect = camera.aspect * this.aspect; - cache.near = camera.near; - cache.far = camera.far; - cache.zoom = camera.zoom; - cache.eyeSep = this.eyeSep; - - // Off-axis stereoscopic effect based on - // http://paulbourke.net/stereographics/stereorender/ - - const projectionMatrix = camera.projectionMatrix.clone(); - const eyeSepHalf = cache.eyeSep / 2; - const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; - const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; - let xmin, xmax; - - // translate xOffset - - _eyeLeft.elements[ 12 ] = - eyeSepHalf; - _eyeRight.elements[ 12 ] = eyeSepHalf; - - // for left eye - - xmin = - ymax * cache.aspect + eyeSepOnProjection; - xmax = ymax * cache.aspect + eyeSepOnProjection; - - projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - - this.cameraL.projectionMatrix.copy( projectionMatrix ); - - // for right eye - - xmin = - ymax * cache.aspect - eyeSepOnProjection; - xmax = ymax * cache.aspect - eyeSepOnProjection; - - projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); - projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - - this.cameraR.projectionMatrix.copy( projectionMatrix ); - - } - - this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); - this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); - - } - - } - - class Clock { - - constructor( autoStart = true ) { - - this.autoStart = autoStart; - - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; - - this.running = false; - - } - - start() { - - this.startTime = now(); - - this.oldTime = this.startTime; - this.elapsedTime = 0; - this.running = true; - - } - - stop() { - - this.getElapsedTime(); - this.running = false; - this.autoStart = false; - - } - - getElapsedTime() { - - this.getDelta(); - return this.elapsedTime; - - } - - getDelta() { - - let diff = 0; - - if ( this.autoStart && ! this.running ) { - - this.start(); - return 0; - - } - - if ( this.running ) { - - const newTime = now(); - - diff = ( newTime - this.oldTime ) / 1000; - this.oldTime = newTime; - - this.elapsedTime += diff; - - } - - return diff; - - } - - } - - function now() { - - return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 - - } - - const _position$1 = /*@__PURE__*/ new Vector3(); - const _quaternion$1 = /*@__PURE__*/ new Quaternion(); - const _scale$1 = /*@__PURE__*/ new Vector3(); - const _orientation$1 = /*@__PURE__*/ new Vector3(); - - class AudioListener extends Object3D { - - constructor() { - - super(); - - this.type = 'AudioListener'; - - this.context = AudioContext.getContext(); - - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); - - this.filter = null; - - this.timeDelta = 0; - - // private - - this._clock = new Clock(); - - } - - getInput() { - - return this.gain; - - } - - removeFilter() { - - if ( this.filter !== null ) { - - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - this.gain.connect( this.context.destination ); - this.filter = null; - - } - - return this; - - } - - getFilter() { - - return this.filter; - - } - - setFilter( value ) { - - if ( this.filter !== null ) { - - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - - } else { - - this.gain.disconnect( this.context.destination ); - - } - - this.filter = value; - this.gain.connect( this.filter ); - this.filter.connect( this.context.destination ); - - return this; - - } - - getMasterVolume() { - - return this.gain.gain.value; - - } - - setMasterVolume( value ) { - - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - - return this; - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - const listener = this.context.listener; - const up = this.up; - - this.timeDelta = this._clock.getDelta(); - - this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); - - _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); - - if ( listener.positionX ) { - - // code path for Chrome (see #14393) - - const endTime = this.context.currentTime + this.timeDelta; - - listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); - listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); - listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); - listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); - listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); - listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); - listener.upX.linearRampToValueAtTime( up.x, endTime ); - listener.upY.linearRampToValueAtTime( up.y, endTime ); - listener.upZ.linearRampToValueAtTime( up.z, endTime ); - - } else { - - listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); - listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); - - } - - } - - } - - class Audio extends Object3D { - - constructor( listener ) { - - super(); - - this.type = 'Audio'; - - this.listener = listener; - this.context = listener.context; - - this.gain = this.context.createGain(); - this.gain.connect( listener.getInput() ); - - this.autoplay = false; - - this.buffer = null; - this.detune = 0; - this.loop = false; - this.loopStart = 0; - this.loopEnd = 0; - this.offset = 0; - this.duration = undefined; - this.playbackRate = 1; - this.isPlaying = false; - this.hasPlaybackControl = true; - this.source = null; - this.sourceType = 'empty'; - - this._startedAt = 0; - this._progress = 0; - this._connected = false; - - this.filters = []; - - } - - getOutput() { - - return this.gain; - - } - - setNodeSource( audioNode ) { - - this.hasPlaybackControl = false; - this.sourceType = 'audioNode'; - this.source = audioNode; - this.connect(); - - return this; - - } - - setMediaElementSource( mediaElement ) { - - this.hasPlaybackControl = false; - this.sourceType = 'mediaNode'; - this.source = this.context.createMediaElementSource( mediaElement ); - this.connect(); - - return this; - - } - - setMediaStreamSource( mediaStream ) { - - this.hasPlaybackControl = false; - this.sourceType = 'mediaStreamNode'; - this.source = this.context.createMediaStreamSource( mediaStream ); - this.connect(); - - return this; - - } - - setBuffer( audioBuffer ) { - - this.buffer = audioBuffer; - this.sourceType = 'buffer'; - - if ( this.autoplay ) this.play(); - - return this; - - } - - play( delay = 0 ) { - - if ( this.isPlaying === true ) { - - console.warn( 'THREE.Audio: Audio is already playing.' ); - return; - - } - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this._startedAt = this.context.currentTime + delay; - - const source = this.context.createBufferSource(); - source.buffer = this.buffer; - source.loop = this.loop; - source.loopStart = this.loopStart; - source.loopEnd = this.loopEnd; - source.onended = this.onEnded.bind( this ); - source.start( this._startedAt, this._progress + this.offset, this.duration ); - - this.isPlaying = true; - - this.source = source; - - this.setDetune( this.detune ); - this.setPlaybackRate( this.playbackRate ); - - return this.connect(); - - } - - pause() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - if ( this.isPlaying === true ) { - - // update current progress - - this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; - - if ( this.loop === true ) { - - // ensure _progress does not exceed duration with looped audios - - this._progress = this._progress % ( this.duration || this.buffer.duration ); - - } - - this.source.stop(); - this.source.onended = null; - - this.isPlaying = false; - - } - - return this; - - } - - stop() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this._progress = 0; - - this.source.stop(); - this.source.onended = null; - this.isPlaying = false; - - return this; - - } - - connect() { - - if ( this.filters.length > 0 ) { - - this.source.connect( this.filters[ 0 ] ); - - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - - this.filters[ i - 1 ].connect( this.filters[ i ] ); - - } - - this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - - } else { - - this.source.connect( this.getOutput() ); - - } - - this._connected = true; - - return this; - - } - - disconnect() { - - if ( this.filters.length > 0 ) { - - this.source.disconnect( this.filters[ 0 ] ); - - for ( let i = 1, l = this.filters.length; i < l; i ++ ) { - - this.filters[ i - 1 ].disconnect( this.filters[ i ] ); - - } - - this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); - - } else { - - this.source.disconnect( this.getOutput() ); - - } - - this._connected = false; - - return this; - - } - - getFilters() { - - return this.filters; - - } - - setFilters( value ) { - - if ( ! value ) value = []; - - if ( this._connected === true ) { - - this.disconnect(); - this.filters = value.slice(); - this.connect(); - - } else { - - this.filters = value.slice(); - - } - - return this; - - } - - setDetune( value ) { - - this.detune = value; - - if ( this.source.detune === undefined ) return; // only set detune when available - - if ( this.isPlaying === true ) { - - this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); - - } - - return this; - - } - - getDetune() { - - return this.detune; - - } - - getFilter() { - - return this.getFilters()[ 0 ]; - - } - - setFilter( filter ) { - - return this.setFilters( filter ? [ filter ] : [] ); - - } - - setPlaybackRate( value ) { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.playbackRate = value; - - if ( this.isPlaying === true ) { - - this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); - - } - - return this; - - } - - getPlaybackRate() { - - return this.playbackRate; - - } - - onEnded() { - - this.isPlaying = false; - - } - - getLoop() { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return false; - - } - - return this.loop; - - } - - setLoop( value ) { - - if ( this.hasPlaybackControl === false ) { - - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; - - } - - this.loop = value; - - if ( this.isPlaying === true ) { - - this.source.loop = this.loop; - - } - - return this; - - } - - setLoopStart( value ) { - - this.loopStart = value; - - return this; - - } - - setLoopEnd( value ) { - - this.loopEnd = value; - - return this; - - } - - getVolume() { - - return this.gain.gain.value; - - } - - setVolume( value ) { - - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - - return this; - - } - - } - - const _position = /*@__PURE__*/ new Vector3(); - const _quaternion = /*@__PURE__*/ new Quaternion(); - const _scale = /*@__PURE__*/ new Vector3(); - const _orientation = /*@__PURE__*/ new Vector3(); - - class PositionalAudio extends Audio { - - constructor( listener ) { - - super( listener ); - - this.panner = this.context.createPanner(); - this.panner.panningModel = 'HRTF'; - this.panner.connect( this.gain ); - - } - - getOutput() { - - return this.panner; - - } - - getRefDistance() { - - return this.panner.refDistance; - - } - - setRefDistance( value ) { - - this.panner.refDistance = value; - - return this; - - } - - getRolloffFactor() { - - return this.panner.rolloffFactor; - - } - - setRolloffFactor( value ) { - - this.panner.rolloffFactor = value; - - return this; - - } - - getDistanceModel() { - - return this.panner.distanceModel; - - } - - setDistanceModel( value ) { - - this.panner.distanceModel = value; - - return this; - - } - - getMaxDistance() { - - return this.panner.maxDistance; - - } - - setMaxDistance( value ) { - - this.panner.maxDistance = value; - - return this; - - } - - setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { - - this.panner.coneInnerAngle = coneInnerAngle; - this.panner.coneOuterAngle = coneOuterAngle; - this.panner.coneOuterGain = coneOuterGain; - - return this; - - } - - updateMatrixWorld( force ) { - - super.updateMatrixWorld( force ); - - if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; - - this.matrixWorld.decompose( _position, _quaternion, _scale ); - - _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); - - const panner = this.panner; - - if ( panner.positionX ) { - - // code path for Chrome and Firefox (see #14393) - - const endTime = this.context.currentTime + this.listener.timeDelta; - - panner.positionX.linearRampToValueAtTime( _position.x, endTime ); - panner.positionY.linearRampToValueAtTime( _position.y, endTime ); - panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); - panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); - panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); - panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); - - } else { - - panner.setPosition( _position.x, _position.y, _position.z ); - panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); - - } - - } - - } - - class AudioAnalyser { - - constructor( audio, fftSize = 2048 ) { - - this.analyser = audio.context.createAnalyser(); - this.analyser.fftSize = fftSize; - - this.data = new Uint8Array( this.analyser.frequencyBinCount ); - - audio.getOutput().connect( this.analyser ); - - } - - - getFrequencyData() { - - this.analyser.getByteFrequencyData( this.data ); - - return this.data; - - } - - getAverageFrequency() { - - let value = 0; - const data = this.getFrequencyData(); - - for ( let i = 0; i < data.length; i ++ ) { - - value += data[ i ]; - - } - - return value / data.length; - - } - - } - - class PropertyMixer { - - constructor( binding, typeName, valueSize ) { - - this.binding = binding; - this.valueSize = valueSize; - - let mixFunction, - mixFunctionAdditive, - setIdentity; - - // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] - // - // interpolators can use .buffer as their .result - // the data then goes to 'incoming' - // - // 'accu0' and 'accu1' are used frame-interleaved for - // the cumulative result and are compared to detect - // changes - // - // 'orig' stores the original state of the property - // - // 'add' is used for additive cumulative results - // - // 'work' is optional and is only present for quaternion types. It is used - // to store intermediate quaternion multiplication results - - switch ( typeName ) { - - case 'quaternion': - mixFunction = this._slerp; - mixFunctionAdditive = this._slerpAdditive; - setIdentity = this._setAdditiveIdentityQuaternion; - - this.buffer = new Float64Array( valueSize * 6 ); - this._workIndex = 5; - break; - - case 'string': - case 'bool': - mixFunction = this._select; - - // Use the regular mix function and for additive on these types, - // additive is not relevant for non-numeric types - mixFunctionAdditive = this._select; - - setIdentity = this._setAdditiveIdentityOther; - - this.buffer = new Array( valueSize * 5 ); - break; - - default: - mixFunction = this._lerp; - mixFunctionAdditive = this._lerpAdditive; - setIdentity = this._setAdditiveIdentityNumeric; - - this.buffer = new Float64Array( valueSize * 5 ); - - } - - this._mixBufferRegion = mixFunction; - this._mixBufferRegionAdditive = mixFunctionAdditive; - this._setIdentity = setIdentity; - this._origIndex = 3; - this._addIndex = 4; - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - this.useCount = 0; - this.referenceCount = 0; - - } - - // accumulate data in the 'incoming' region into 'accu' - accumulate( accuIndex, weight ) { - - // note: happily accumulating nothing when weight = 0, the caller knows - // the weight and shouldn't have made the call in the first place - - const buffer = this.buffer, - stride = this.valueSize, - offset = accuIndex * stride + stride; - - let currentWeight = this.cumulativeWeight; - - if ( currentWeight === 0 ) { - - // accuN := incoming * weight - - for ( let i = 0; i !== stride; ++ i ) { - - buffer[ offset + i ] = buffer[ i ]; - - } - - currentWeight = weight; - - } else { - - // accuN := accuN + incoming * weight - - currentWeight += weight; - const mix = weight / currentWeight; - this._mixBufferRegion( buffer, offset, 0, mix, stride ); - - } - - this.cumulativeWeight = currentWeight; - - } - - // accumulate data in the 'incoming' region into 'add' - accumulateAdditive( weight ) { - - const buffer = this.buffer, - stride = this.valueSize, - offset = stride * this._addIndex; - - if ( this.cumulativeWeightAdditive === 0 ) { - - // add = identity - - this._setIdentity(); - - } - - // add := add + incoming * weight - - this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); - this.cumulativeWeightAdditive += weight; - - } - - // apply the state of 'accu' to the binding when accus differ - apply( accuIndex ) { - - const stride = this.valueSize, - buffer = this.buffer, - offset = accuIndex * stride + stride, - - weight = this.cumulativeWeight, - weightAdditive = this.cumulativeWeightAdditive, - - binding = this.binding; - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - if ( weight < 1 ) { - - // accuN := accuN + original * ( 1 - cumulativeWeight ) - - const originalValueOffset = stride * this._origIndex; - - this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); - - } - - if ( weightAdditive > 0 ) { - - // accuN := accuN + additive accuN - - this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); - - } - - for ( let i = stride, e = stride + stride; i !== e; ++ i ) { - - if ( buffer[ i ] !== buffer[ i + stride ] ) { - - // value has changed -> update scene graph - - binding.setValue( buffer, offset ); - break; - - } - - } - - } - - // remember the state of the bound property and copy it to both accus - saveOriginalState() { - - const binding = this.binding; - - const buffer = this.buffer, - stride = this.valueSize, - - originalValueOffset = stride * this._origIndex; - - binding.getValue( buffer, originalValueOffset ); - - // accu[0..1] := orig -- initially detect changes against the original - for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { - - buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; - - } - - // Add to identity for additive - this._setIdentity(); - - this.cumulativeWeight = 0; - this.cumulativeWeightAdditive = 0; - - } - - // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState() { - - const originalValueOffset = this.valueSize * 3; - this.binding.setValue( this.buffer, originalValueOffset ); - - } - - _setAdditiveIdentityNumeric() { - - const startIndex = this._addIndex * this.valueSize; - const endIndex = startIndex + this.valueSize; - - for ( let i = startIndex; i < endIndex; i ++ ) { - - this.buffer[ i ] = 0; - - } - - } - - _setAdditiveIdentityQuaternion() { - - this._setAdditiveIdentityNumeric(); - this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; - - } - - _setAdditiveIdentityOther() { - - const startIndex = this._origIndex * this.valueSize; - const targetIndex = this._addIndex * this.valueSize; - - for ( let i = 0; i < this.valueSize; i ++ ) { - - this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; - - } - - } - - - // mix functions - - _select( buffer, dstOffset, srcOffset, t, stride ) { - - if ( t >= 0.5 ) { - - for ( let i = 0; i !== stride; ++ i ) { - - buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; - - } - - } - - } - - _slerp( buffer, dstOffset, srcOffset, t ) { - - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); - - } - - _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - - const workOffset = this._workIndex * stride; - - // Store result in intermediate buffer offset - Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); - - // Slerp to the intermediate result - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); - - } - - _lerp( buffer, dstOffset, srcOffset, t, stride ) { - - const s = 1 - t; - - for ( let i = 0; i !== stride; ++ i ) { - - const j = dstOffset + i; - - buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; - - } - - } - - _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { - - for ( let i = 0; i !== stride; ++ i ) { - - const j = dstOffset + i; - - buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; - - } - - } - - } - - // Characters [].:/ are reserved for track binding syntax. - const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; - const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); - - // Attempts to allow node names from any language. ES5's `\w` regexp matches - // only latin characters, and the unicode \p{L} is not yet supported. So - // instead, we exclude reserved characters and match everything else. - const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; - const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; - - // Parent directories, delimited by '/' or ':'. Currently unused, but must - // be matched to parse the rest of the track name. - const _directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); - - // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. - const _nodeRe = /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); - - // Object on target node, and accessor. May not contain reserved - // characters. Accessor may contain any character except closing bracket. - const _objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); - - // Property and accessor. May not contain reserved characters. Accessor may - // contain any non-bracket characters. - const _propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); - - const _trackRe = new RegExp( '' - + '^' - + _directoryRe - + _nodeRe - + _objectRe - + _propertyRe - + '$' - ); - - const _supportedObjectNames = [ 'material', 'materials', 'bones' ]; - - class Composite { - - constructor( targetGroup, path, optionalParsedPath ) { - - const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); - - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); - - } - - getValue( array, offset ) { - - this.bind(); // bind all binding - - const firstValidIndex = this._targetGroup.nCachedObjects_, - binding = this._bindings[ firstValidIndex ]; - - // and only call .getValue on the first - if ( binding !== undefined ) binding.getValue( array, offset ); - - } - - setValue( array, offset ) { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].setValue( array, offset ); - - } - - } - - bind() { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].bind(); - - } - - } - - unbind() { - - const bindings = this._bindings; - - for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - - bindings[ i ].unbind(); - - } - - } - - } - - // Note: This class uses a State pattern on a per-method basis: - // 'bind' sets 'this.getValue' / 'setValue' and shadows the - // prototype version of these methods with one that represents - // the bound state. When the property is not found, the methods - // become no-ops. - class PropertyBinding { - - constructor( rootNode, path, parsedPath ) { - - this.path = path; - this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - - this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; - - this.rootNode = rootNode; - - // initial state of these methods that calls 'bind' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; - - } - - - static create( root, path, parsedPath ) { - - if ( ! ( root && root.isAnimationObjectGroup ) ) { - - return new PropertyBinding( root, path, parsedPath ); - - } else { - - return new PropertyBinding.Composite( root, path, parsedPath ); - - } - - } - - /** - * Replaces spaces with underscores and removes unsupported characters from - * node names, to ensure compatibility with parseTrackName(). - * - * @param {string} name Node name to be sanitized. - * @return {string} - */ - static sanitizeNodeName( name ) { - - return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); - - } - - static parseTrackName( trackName ) { - - const matches = _trackRe.exec( trackName ); - - if ( ! matches ) { - - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); - - } - - const results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], // required - propertyIndex: matches[ 6 ] - }; - - const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); - - if ( lastDot !== undefined && lastDot !== - 1 ) { - - const objectName = results.nodeName.substring( lastDot + 1 ); - - // Object names must be checked against an allowlist. Otherwise, there - // is no way to parse 'foo.bar.baz': 'baz' must be a property, but - // 'bar' could be the objectName, or part of a nodeName (which can - // include '.' characters). - if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { - - results.nodeName = results.nodeName.substring( 0, lastDot ); - results.objectName = objectName; - - } - - } - - if ( results.propertyName === null || results.propertyName.length === 0 ) { - - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); - - } - - return results; - - } - - static findNode( root, nodeName ) { - - if ( ! nodeName || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { - - return root; - - } - - // search into skeleton bones. - if ( root.skeleton ) { - - const bone = root.skeleton.getBoneByName( nodeName ); - - if ( bone !== undefined ) { - - return bone; - - } - - } - - // search into node subtree. - if ( root.children ) { - - const searchNodeSubtree = function ( children ) { - - for ( let i = 0; i < children.length; i ++ ) { - - const childNode = children[ i ]; - - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - - return childNode; - - } - - const result = searchNodeSubtree( childNode.children ); - - if ( result ) return result; - - } - - return null; - - }; - - const subTreeNode = searchNodeSubtree( root.children ); - - if ( subTreeNode ) { - - return subTreeNode; - - } - - } - - return null; - - } - - // these are used to "bind" a nonexistent property - _getValue_unavailable() {} - _setValue_unavailable() {} - - // Getters - - _getValue_direct( buffer, offset ) { - - buffer[ offset ] = this.targetObject[ this.propertyName ]; - - } - - _getValue_array( buffer, offset ) { - - const source = this.resolvedProperty; - - for ( let i = 0, n = source.length; i !== n; ++ i ) { - - buffer[ offset ++ ] = source[ i ]; - - } - - } - - _getValue_arrayElement( buffer, offset ) { - - buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; - - } - - _getValue_toArray( buffer, offset ) { - - this.resolvedProperty.toArray( buffer, offset ); - - } - - // Direct - - _setValue_direct( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - - } - - _setValue_direct_setNeedsUpdate( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - } - - _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // EntireArray - - _setValue_array( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - } - - _setValue_array_setNeedsUpdate( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - this.targetObject.needsUpdate = true; - - } - - _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { - - const dest = this.resolvedProperty; - - for ( let i = 0, n = dest.length; i !== n; ++ i ) { - - dest[ i ] = buffer[ offset ++ ]; - - } - - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // ArrayElement - - _setValue_arrayElement( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - - } - - _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; - - } - - _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - // HasToFromArray - - _setValue_fromArray( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - - } - - _setValue_fromArray_setNeedsUpdate( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.needsUpdate = true; - - } - - _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { - - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.matrixWorldNeedsUpdate = true; - - } - - _getValue_unbound( targetArray, offset ) { - - this.bind(); - this.getValue( targetArray, offset ); - - } - - _setValue_unbound( sourceArray, offset ) { - - this.bind(); - this.setValue( sourceArray, offset ); - - } - - // create getter / setter pair for a property in the scene graph - bind() { - - let targetObject = this.node; - const parsedPath = this.parsedPath; - - const objectName = parsedPath.objectName; - const propertyName = parsedPath.propertyName; - let propertyIndex = parsedPath.propertyIndex; - - if ( ! targetObject ) { - - targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode; - - this.node = targetObject; - - } - - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; - - // ensure there is a value node - if ( ! targetObject ) { - - console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' ); - return; - - } - - if ( objectName ) { - - let objectIndex = parsedPath.objectIndex; - - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { - - case 'materials': - - if ( ! targetObject.material ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; - - } - - if ( ! targetObject.material.materials ) { - - console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); - return; - - } - - targetObject = targetObject.material.materials; - - break; - - case 'bones': - - if ( ! targetObject.skeleton ) { - - console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); - return; - - } - - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. - - targetObject = targetObject.skeleton.bones; - - // support resolving morphTarget names into indices. - for ( let i = 0; i < targetObject.length; i ++ ) { - - if ( targetObject[ i ].name === objectIndex ) { - - objectIndex = i; - break; - - } - - } - - break; - - default: - - if ( targetObject[ objectName ] === undefined ) { - - console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); - return; - - } - - targetObject = targetObject[ objectName ]; - - } - - - if ( objectIndex !== undefined ) { - - if ( targetObject[ objectIndex ] === undefined ) { - - console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); - return; - - } - - targetObject = targetObject[ objectIndex ]; - - } - - } - - // resolve property - const nodeProperty = targetObject[ propertyName ]; - - if ( nodeProperty === undefined ) { - - const nodeName = parsedPath.nodeName; - - console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + - '.' + propertyName + ' but it wasn\'t found.', targetObject ); - return; - - } - - // determine versioning scheme - let versioning = this.Versioning.None; - - this.targetObject = targetObject; - - if ( targetObject.needsUpdate !== undefined ) { // material - - versioning = this.Versioning.NeedsUpdate; - - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform - - versioning = this.Versioning.MatrixWorldNeedsUpdate; - - } - - // determine how the property gets bound - let bindingType = this.BindingType.Direct; - - if ( propertyIndex !== undefined ) { - - // access a sub element of the property array (only primitives are supported right now) - - if ( propertyName === 'morphTargetInfluences' ) { - - // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. - - // support resolving morphTarget names into indices. - if ( ! targetObject.geometry ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); - return; - - } - - if ( targetObject.geometry.isBufferGeometry ) { - - if ( ! targetObject.geometry.morphAttributes ) { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); - return; - - } - - if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { - - propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; - - } - - - } else { - - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences on THREE.Geometry. Use THREE.BufferGeometry instead.', this ); - return; - - } - - } - - bindingType = this.BindingType.ArrayElement; - - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; - - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - - // must use copy for Object3D.Euler/Quaternion - - bindingType = this.BindingType.HasFromToArray; - - this.resolvedProperty = nodeProperty; - - } else if ( Array.isArray( nodeProperty ) ) { - - bindingType = this.BindingType.EntireArray; - - this.resolvedProperty = nodeProperty; - - } else { - - this.propertyName = propertyName; - - } - - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; - - } - - unbind() { - - this.node = null; - - // back to the prototype version of getValue / setValue - // note: avoiding to mutate the shape of 'this' via 'delete' - this.getValue = this._getValue_unbound; - this.setValue = this._setValue_unbound; - - } - - } - - PropertyBinding.Composite = Composite; - - PropertyBinding.prototype.BindingType = { - Direct: 0, - EntireArray: 1, - ArrayElement: 2, - HasFromToArray: 3 - }; - - PropertyBinding.prototype.Versioning = { - None: 0, - NeedsUpdate: 1, - MatrixWorldNeedsUpdate: 2 - }; - - PropertyBinding.prototype.GetterByBindingType = [ - - PropertyBinding.prototype._getValue_direct, - PropertyBinding.prototype._getValue_array, - PropertyBinding.prototype._getValue_arrayElement, - PropertyBinding.prototype._getValue_toArray, - - ]; - - PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ - - [ - // Direct - PropertyBinding.prototype._setValue_direct, - PropertyBinding.prototype._setValue_direct_setNeedsUpdate, - PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, - - ], [ - - // EntireArray - - PropertyBinding.prototype._setValue_array, - PropertyBinding.prototype._setValue_array_setNeedsUpdate, - PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, - - ], [ - - // ArrayElement - PropertyBinding.prototype._setValue_arrayElement, - PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, - PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, - - ], [ - - // HasToFromArray - PropertyBinding.prototype._setValue_fromArray, - PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, - PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, - - ] - - ]; - - /** - * - * A group of objects that receives a shared animation state. - * - * Usage: - * - * - Add objects you would otherwise pass as 'root' to the - * constructor or the .clipAction method of AnimationMixer. - * - * - Instead pass this object as 'root'. - * - * - You can also add and remove objects later when the mixer - * is running. - * - * Note: - * - * Objects of this class appear as one object to the mixer, - * so cache control of the individual objects must be done - * on the group. - * - * Limitation: - * - * - The animated properties must be compatible among the - * all objects in the group. - * - * - A single property can either be controlled through a - * target group or directly, but not both. - */ - - class AnimationObjectGroup { - - constructor() { - - this.uuid = generateUUID(); - - // cached objects followed by the active ones - this._objects = Array.prototype.slice.call( arguments ); - - this.nCachedObjects_ = 0; // threshold - // note: read by PropertyBinding.Composite - - const indices = {}; - this._indicesByUUID = indices; // for bookkeeping - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - indices[ arguments[ i ].uuid ] = i; - - } - - this._paths = []; // inside: string - this._parsedPaths = []; // inside: { we don't care, here } - this._bindings = []; // inside: Array< PropertyBinding > - this._bindingsIndicesByPath = {}; // inside: indices in these arrays - - const scope = this; - - this.stats = { - - objects: { - get total() { - - return scope._objects.length; - - }, - get inUse() { - - return this.total - scope.nCachedObjects_; - - } - }, - get bindingsPerObject() { - - return scope._bindings.length; - - } - - }; - - } - - add() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - nBindings = bindings.length; - - let knownObject = undefined, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid; - let index = indicesByUUID[ uuid ]; - - if ( index === undefined ) { - - // unknown object -> add it to the ACTIVE region - - index = nObjects ++; - indicesByUUID[ uuid ] = index; - objects.push( object ); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); - - } - - } else if ( index < nCachedObjects ) { - - knownObject = objects[ index ]; - - // move existing object to the ACTIVE region - - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ]; - - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; - - indicesByUUID[ uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = object; - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ]; - - let binding = bindingsForPath[ index ]; - - bindingsForPath[ index ] = lastCached; - - if ( binding === undefined ) { - - // since we do not bother to create new bindings - // for objects that are cached, the binding may - // or may not exist - - binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); - - } - - bindingsForPath[ firstActiveIndex ] = binding; - - } - - } else if ( objects[ index ] !== knownObject ) { - - console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + - 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); - - } // else the object is already where we want it to be - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - remove() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; - - let nCachedObjects = this.nCachedObjects_; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; - - if ( index !== undefined && index >= nCachedObjects ) { - - // move existing object into the CACHED region - - const lastCachedIndex = nCachedObjects ++, - firstActiveObject = objects[ lastCachedIndex ]; - - indicesByUUID[ firstActiveObject.uuid ] = index; - objects[ index ] = firstActiveObject; - - indicesByUUID[ uuid ] = lastCachedIndex; - objects[ lastCachedIndex ] = object; - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - firstActive = bindingsForPath[ lastCachedIndex ], - binding = bindingsForPath[ index ]; - - bindingsForPath[ index ] = firstActive; - bindingsForPath[ lastCachedIndex ] = binding; - - } - - } - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - // remove & forget - uncache() { - - const objects = this._objects, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; - - let nCachedObjects = this.nCachedObjects_, - nObjects = objects.length; - - for ( let i = 0, n = arguments.length; i !== n; ++ i ) { - - const object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; - - if ( index !== undefined ) { - - delete indicesByUUID[ uuid ]; - - if ( index < nCachedObjects ) { - - // object is cached, shrink the CACHED region - - const firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ], - lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; - - // last cached object takes this object's place - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; - - // last object goes to the activated slot and pop - indicesByUUID[ lastObject.uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = lastObject; - objects.pop(); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - last = bindingsForPath[ lastIndex ]; - - bindingsForPath[ index ] = lastCached; - bindingsForPath[ firstActiveIndex ] = last; - bindingsForPath.pop(); - - } - - } else { - - // object is active, just swap with the last and pop - - const lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; - - if ( lastIndex > 0 ) { - - indicesByUUID[ lastObject.uuid ] = index; - - } - - objects[ index ] = lastObject; - objects.pop(); - - // accounting is done, now do the same for all bindings - - for ( let j = 0, m = nBindings; j !== m; ++ j ) { - - const bindingsForPath = bindings[ j ]; - - bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; - bindingsForPath.pop(); - - } - - } // cached or active - - } // if object is known - - } // for arguments - - this.nCachedObjects_ = nCachedObjects; - - } - - // Internal interface used by befriended PropertyBinding.Composite: - - subscribe_( path, parsedPath ) { - - // returns an array of bindings for the given path that is changed - // according to the contained objects in the group - - const indicesByPath = this._bindingsIndicesByPath; - let index = indicesByPath[ path ]; - const bindings = this._bindings; - - if ( index !== undefined ) return bindings[ index ]; - - const paths = this._paths, - parsedPaths = this._parsedPaths, - objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - bindingsForPath = new Array( nObjects ); - - index = bindings.length; - - indicesByPath[ path ] = index; - - paths.push( path ); - parsedPaths.push( parsedPath ); - bindings.push( bindingsForPath ); - - for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { - - const object = objects[ i ]; - bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); - - } - - return bindingsForPath; - - } - - unsubscribe_( path ) { - - // tells the group to forget about a property path and no longer - // update the array previously obtained with 'subscribe_' - - const indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ]; - - if ( index !== undefined ) { - - const paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - lastBindingsIndex = bindings.length - 1, - lastBindings = bindings[ lastBindingsIndex ], - lastBindingsPath = path[ lastBindingsIndex ]; - - indicesByPath[ lastBindingsPath ] = index; - - bindings[ index ] = lastBindings; - bindings.pop(); - - parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; - parsedPaths.pop(); - - paths[ index ] = paths[ lastBindingsIndex ]; - paths.pop(); - - } - - } - - } - - AnimationObjectGroup.prototype.isAnimationObjectGroup = true; - - class AnimationAction { - - constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { - - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot; - this.blendMode = blendMode; - - const tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); - - const interpolantSettings = { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - }; - - for ( let i = 0; i !== nTracks; ++ i ) { - - const interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; - - } - - this._interpolantSettings = interpolantSettings; - - this._interpolants = interpolants; // bound by the mixer - - // inside: PropertyMixer (managed by the mixer) - this._propertyBindings = new Array( nTracks ); - - this._cacheIndex = null; // for the memory manager - this._byClipCacheIndex = null; // for the memory manager - - this._timeScaleInterpolant = null; - this._weightInterpolant = null; - - this.loop = LoopRepeat; - this._loopCount = - 1; - - // global mixer time when the action is to be started - // it's set back to 'null' upon start of the action - this._startTime = null; - - // scaled local time of the action - // gets clamped or wrapped to 0..clip.duration according to loop - this.time = 0; - - this.timeScale = 1; - this._effectiveTimeScale = 1; - - this.weight = 1; - this._effectiveWeight = 1; - - this.repetitions = Infinity; // no. of repetitions when looping - - this.paused = false; // true -> zero effective time scale - this.enabled = true; // false -> zero effective weight - - this.clampWhenFinished = false;// keep feeding the last frame? - - this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true;// clips for start, loop and end - - } - - // State & Scheduling - - play() { - - this._mixer._activateAction( this ); - - return this; - - } - - stop() { - - this._mixer._deactivateAction( this ); - - return this.reset(); - - } - - reset() { - - this.paused = false; - this.enabled = true; - - this.time = 0; // restart clip - this._loopCount = - 1;// forget previous loops - this._startTime = null;// forget scheduling - - return this.stopFading().stopWarping(); - - } - - isRunning() { - - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); - - } - - // return true when play has been called - isScheduled() { - - return this._mixer._isActiveAction( this ); - - } - - startAt( time ) { - - this._startTime = time; - - return this; - - } - - setLoop( mode, repetitions ) { - - this.loop = mode; - this.repetitions = repetitions; - - return this; - - } - - // Weight - - // set the weight stopping any scheduled fading - // although .enabled = false yields an effective weight of zero, this - // method does *not* change .enabled, because it would be confusing - setEffectiveWeight( weight ) { - - this.weight = weight; - - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; - - return this.stopFading(); - - } - - // return the weight considering fading and .enabled - getEffectiveWeight() { - - return this._effectiveWeight; - - } - - fadeIn( duration ) { - - return this._scheduleFading( duration, 0, 1 ); - - } - - fadeOut( duration ) { - - return this._scheduleFading( duration, 1, 0 ); - - } - - crossFadeFrom( fadeOutAction, duration, warp ) { - - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); - - if ( warp ) { - - const fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, - - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; - - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); - - } - - return this; - - } - - crossFadeTo( fadeInAction, duration, warp ) { - - return fadeInAction.crossFadeFrom( this, duration, warp ); - - } - - stopFading() { - - const weightInterpolant = this._weightInterpolant; - - if ( weightInterpolant !== null ) { - - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); - - } - - return this; - - } - - // Time Scale Control - - // set the time scale stopping any scheduled warping - // although .paused = true yields an effective time scale of zero, this - // method does *not* change .paused, because it would be confusing - setEffectiveTimeScale( timeScale ) { - - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 : timeScale; - - return this.stopWarping(); - - } - - // return the time scale considering warping and .paused - getEffectiveTimeScale() { - - return this._effectiveTimeScale; - - } - - setDuration( duration ) { - - this.timeScale = this._clip.duration / duration; - - return this.stopWarping(); - - } - - syncWith( action ) { - - this.time = action.time; - this.timeScale = action.timeScale; - - return this.stopWarping(); - - } - - halt( duration ) { - - return this.warp( this._effectiveTimeScale, 0, duration ); - - } - - warp( startTimeScale, endTimeScale, duration ) { - - const mixer = this._mixer, - now = mixer.time, - timeScale = this.timeScale; - - let interpolant = this._timeScaleInterpolant; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(); - this._timeScaleInterpolant = interpolant; - - } - - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - times[ 1 ] = now + duration; - - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; - - return this; - - } - - stopWarping() { - - const timeScaleInterpolant = this._timeScaleInterpolant; - - if ( timeScaleInterpolant !== null ) { - - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); - - } - - return this; - - } - - // Object Accessors - - getMixer() { - - return this._mixer; - - } - - getClip() { - - return this._clip; - - } - - getRoot() { - - return this._localRoot || this._mixer._root; - - } - - // Interna - - _update( time, deltaTime, timeDirection, accuIndex ) { - - // called by the mixer - - if ( ! this.enabled ) { - - // call ._updateWeight() to update ._effectiveWeight - - this._updateWeight( time ); - return; - - } - - const startTime = this._startTime; - - if ( startTime !== null ) { - - // check for scheduled start of action - - const timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { - - return; // yet to come / don't decide when delta = 0 - - } - - // start - - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; - - } - - // apply time scale and advance time - - deltaTime *= this._updateTimeScale( time ); - const clipTime = this._updateTime( deltaTime ); - - // note: _updateTime may disable the action resulting in - // an effective weight of 0 - - const weight = this._updateWeight( time ); - - if ( weight > 0 ) { - - const interpolants = this._interpolants; - const propertyMixers = this._propertyBindings; - - switch ( this.blendMode ) { - - case AdditiveAnimationBlendMode: - - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulateAdditive( weight ); - - } - - break; - - case NormalAnimationBlendMode: - default: - - for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { - - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); - - } - - } - - } - - } - - _updateWeight( time ) { - - let weight = 0; - - if ( this.enabled ) { - - weight = this.weight; - const interpolant = this._weightInterpolant; - - if ( interpolant !== null ) { - - const interpolantValue = interpolant.evaluate( time )[ 0 ]; - - weight *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopFading(); - - if ( interpolantValue === 0 ) { - - // faded out, disable - this.enabled = false; - - } - - } - - } - - } - - this._effectiveWeight = weight; - return weight; - - } - - _updateTimeScale( time ) { - - let timeScale = 0; - - if ( ! this.paused ) { - - timeScale = this.timeScale; - - const interpolant = this._timeScaleInterpolant; - - if ( interpolant !== null ) { - - const interpolantValue = interpolant.evaluate( time )[ 0 ]; - - timeScale *= interpolantValue; - - if ( time > interpolant.parameterPositions[ 1 ] ) { - - this.stopWarping(); - - if ( timeScale === 0 ) { - - // motion has halted, pause - this.paused = true; - - } else { - - // warp done - apply final time scale - this.timeScale = timeScale; - - } - - } - - } - - } - - this._effectiveTimeScale = timeScale; - return timeScale; - - } - - _updateTime( deltaTime ) { - - const duration = this._clip.duration; - const loop = this.loop; - - let time = this.time + deltaTime; - let loopCount = this._loopCount; - - const pingPong = ( loop === LoopPingPong ); - - if ( deltaTime === 0 ) { - - if ( loopCount === - 1 ) return time; - - return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; - - } - - if ( loop === LoopOnce ) { - - if ( loopCount === - 1 ) { - - // just started - - this._loopCount = 0; - this._setEndings( true, true, false ); - - } - - handle_stop: { - - if ( time >= duration ) { - - time = duration; - - } else if ( time < 0 ) { - - time = 0; - - } else { - - this.time = time; - - break handle_stop; - - } - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? - 1 : 1 - } ); - - } - - } else { // repetitive Repeat or PingPong - - if ( loopCount === - 1 ) { - - // just started - - if ( deltaTime >= 0 ) { - - loopCount = 0; - - this._setEndings( true, this.repetitions === 0, pingPong ); - - } else { - - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 - - this._setEndings( this.repetitions === 0, true, pingPong ); - - } - - } - - if ( time >= duration || time < 0 ) { - - // wrap around - - const loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; - - loopCount += Math.abs( loopDelta ); - - const pending = this.repetitions - loopCount; - - if ( pending <= 0 ) { - - // have to stop (switch state, clamp time, fire event) - - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; - - time = deltaTime > 0 ? duration : 0; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : - 1 - } ); - - } else { - - // keep running - - if ( pending === 1 ) { - - // entering the last round - - const atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); - - } else { - - this._setEndings( false, false, pingPong ); - - } - - this._loopCount = loopCount; - - this.time = time; - - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); - - } - - } else { - - this.time = time; - - } - - if ( pingPong && ( loopCount & 1 ) === 1 ) { - - // invert time for the "pong round" - - return duration - time; - - } - - } - - return time; - - } - - _setEndings( atStart, atEnd, pingPong ) { - - const settings = this._interpolantSettings; - - if ( pingPong ) { - - settings.endingStart = ZeroSlopeEnding; - settings.endingEnd = ZeroSlopeEnding; - - } else { - - // assuming for LoopOnce atStart == atEnd == true - - if ( atStart ) { - - settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { - - settings.endingStart = WrapAroundEnding; - - } - - if ( atEnd ) { - - settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { - - settings.endingEnd = WrapAroundEnding; - - } - - } - - } - - _scheduleFading( duration, weightNow, weightThen ) { - - const mixer = this._mixer, now = mixer.time; - let interpolant = this._weightInterpolant; - - if ( interpolant === null ) { - - interpolant = mixer._lendControlInterpolant(); - this._weightInterpolant = interpolant; - - } - - const times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - values[ 0 ] = weightNow; - times[ 1 ] = now + duration; - values[ 1 ] = weightThen; - - return this; - - } - - } - - class AnimationMixer extends EventDispatcher { - - constructor( root ) { - - super(); - - this._root = root; - this._initMemoryManager(); - this._accuIndex = 0; - this.time = 0; - this.timeScale = 1.0; - - } - - _bindAction( action, prototypeAction ) { - - const root = action._localRoot || this._root, - tracks = action._clip.tracks, - nTracks = tracks.length, - bindings = action._propertyBindings, - interpolants = action._interpolants, - rootUuid = root.uuid, - bindingsByRoot = this._bindingsByRootAndName; - - let bindingsByName = bindingsByRoot[ rootUuid ]; - - if ( bindingsByName === undefined ) { - - bindingsByName = {}; - bindingsByRoot[ rootUuid ] = bindingsByName; - - } - - for ( let i = 0; i !== nTracks; ++ i ) { - - const track = tracks[ i ], - trackName = track.name; - - let binding = bindingsByName[ trackName ]; - - if ( binding !== undefined ) { - - bindings[ i ] = binding; - - } else { - - binding = bindings[ i ]; - - if ( binding !== undefined ) { - - // existing binding, make sure the cache knows - - if ( binding._cacheIndex === null ) { - - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); - - } - - continue; - - } - - const path = prototypeAction && prototypeAction. - _propertyBindings[ i ].binding.parsedPath; - - binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); - - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); - - bindings[ i ] = binding; - - } - - interpolants[ i ].resultBuffer = binding.buffer; - - } - - } - - _activateAction( action ) { - - if ( ! this._isActiveAction( action ) ) { - - if ( action._cacheIndex === null ) { - - // this action has been forgotten by the cache, but the user - // appears to be still using it -> rebind - - const rootUuid = ( action._localRoot || this._root ).uuid, - clipUuid = action._clip.uuid, - actionsForClip = this._actionsByClip[ clipUuid ]; - - this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); - - this._addInactiveAction( action, clipUuid, rootUuid ); - - } - - const bindings = action._propertyBindings; - - // increment reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( binding.useCount ++ === 0 ) { - - this._lendBinding( binding ); - binding.saveOriginalState(); - - } - - } - - this._lendAction( action ); - - } - - } - - _deactivateAction( action ) { - - if ( this._isActiveAction( action ) ) { - - const bindings = action._propertyBindings; - - // decrement reference counts / sort out state - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( -- binding.useCount === 0 ) { - - binding.restoreOriginalState(); - this._takeBackBinding( binding ); - - } - - } - - this._takeBackAction( action ); - - } - - } - - // Memory manager - - _initMemoryManager() { - - this._actions = []; // 'nActiveActions' followed by inactive ones - this._nActiveActions = 0; - - this._actionsByClip = {}; - // inside: - // { - // knownActions: Array< AnimationAction > - used as prototypes - // actionByRoot: AnimationAction - lookup - // } - - - this._bindings = []; // 'nActiveBindings' followed by inactive ones - this._nActiveBindings = 0; - - this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > - - - this._controlInterpolants = []; // same game as above - this._nActiveControlInterpolants = 0; - - const scope = this; - - this.stats = { - - actions: { - get total() { - - return scope._actions.length; - - }, - get inUse() { - - return scope._nActiveActions; - - } - }, - bindings: { - get total() { - - return scope._bindings.length; - - }, - get inUse() { - - return scope._nActiveBindings; - - } - }, - controlInterpolants: { - get total() { - - return scope._controlInterpolants.length; - - }, - get inUse() { - - return scope._nActiveControlInterpolants; - - } - } - - }; - - } - - // Memory management for AnimationAction objects - - _isActiveAction( action ) { - - const index = action._cacheIndex; - return index !== null && index < this._nActiveActions; - - } - - _addInactiveAction( action, clipUuid, rootUuid ) { - - const actions = this._actions, - actionsByClip = this._actionsByClip; - - let actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip === undefined ) { - - actionsForClip = { - - knownActions: [ action ], - actionByRoot: {} - - }; - - action._byClipCacheIndex = 0; - - actionsByClip[ clipUuid ] = actionsForClip; - - } else { - - const knownActions = actionsForClip.knownActions; - - action._byClipCacheIndex = knownActions.length; - knownActions.push( action ); - - } - - action._cacheIndex = actions.length; - actions.push( action ); - - actionsForClip.actionByRoot[ rootUuid ] = action; - - } - - _removeInactiveAction( action ) { - - const actions = this._actions, - lastInactiveAction = actions[ actions.length - 1 ], - cacheIndex = action._cacheIndex; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - action._cacheIndex = null; - - - const clipUuid = action._clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ], - knownActionsForClip = actionsForClip.knownActions, - - lastKnownAction = - knownActionsForClip[ knownActionsForClip.length - 1 ], - - byClipCacheIndex = action._byClipCacheIndex; - - lastKnownAction._byClipCacheIndex = byClipCacheIndex; - knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; - knownActionsForClip.pop(); - - action._byClipCacheIndex = null; - - - const actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( action._localRoot || this._root ).uuid; - - delete actionByRoot[ rootUuid ]; - - if ( knownActionsForClip.length === 0 ) { - - delete actionsByClip[ clipUuid ]; - - } - - this._removeInactiveBindingsForAction( action ); - - } - - _removeInactiveBindingsForAction( action ) { - - const bindings = action._propertyBindings; - - for ( let i = 0, n = bindings.length; i !== n; ++ i ) { - - const binding = bindings[ i ]; - - if ( -- binding.referenceCount === 0 ) { - - this._removeInactiveBinding( binding ); - - } - - } - - } - - _lendAction( action ) { - - // [ active actions | inactive actions ] - // [ active actions >| inactive actions ] - // s a - // <-swap-> - // a s - - const actions = this._actions, - prevIndex = action._cacheIndex, - - lastActiveIndex = this._nActiveActions ++, - - firstInactiveAction = actions[ lastActiveIndex ]; - - action._cacheIndex = lastActiveIndex; - actions[ lastActiveIndex ] = action; - - firstInactiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = firstInactiveAction; - - } - - _takeBackAction( action ) { - - // [ active actions | inactive actions ] - // [ active actions |< inactive actions ] - // a s - // <-swap-> - // s a - - const actions = this._actions, - prevIndex = action._cacheIndex, - - firstInactiveIndex = -- this._nActiveActions, - - lastActiveAction = actions[ firstInactiveIndex ]; - - action._cacheIndex = firstInactiveIndex; - actions[ firstInactiveIndex ] = action; - - lastActiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = lastActiveAction; - - } - - // Memory management for PropertyMixer objects - - _addInactiveBinding( binding, rootUuid, trackName ) { - - const bindingsByRoot = this._bindingsByRootAndName, - bindings = this._bindings; - - let bindingByName = bindingsByRoot[ rootUuid ]; - - if ( bindingByName === undefined ) { - - bindingByName = {}; - bindingsByRoot[ rootUuid ] = bindingByName; - - } - - bindingByName[ trackName ] = binding; - - binding._cacheIndex = bindings.length; - bindings.push( binding ); - - } - - _removeInactiveBinding( binding ) { - - const bindings = this._bindings, - propBinding = binding.binding, - rootUuid = propBinding.rootNode.uuid, - trackName = propBinding.path, - bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], - - lastInactiveBinding = bindings[ bindings.length - 1 ], - cacheIndex = binding._cacheIndex; - - lastInactiveBinding._cacheIndex = cacheIndex; - bindings[ cacheIndex ] = lastInactiveBinding; - bindings.pop(); - - delete bindingByName[ trackName ]; - - if ( Object.keys( bindingByName ).length === 0 ) { - - delete bindingsByRoot[ rootUuid ]; - - } - - } - - _lendBinding( binding ) { - - const bindings = this._bindings, - prevIndex = binding._cacheIndex, - - lastActiveIndex = this._nActiveBindings ++, - - firstInactiveBinding = bindings[ lastActiveIndex ]; - - binding._cacheIndex = lastActiveIndex; - bindings[ lastActiveIndex ] = binding; - - firstInactiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = firstInactiveBinding; - - } - - _takeBackBinding( binding ) { - - const bindings = this._bindings, - prevIndex = binding._cacheIndex, - - firstInactiveIndex = -- this._nActiveBindings, - - lastActiveBinding = bindings[ firstInactiveIndex ]; - - binding._cacheIndex = firstInactiveIndex; - bindings[ firstInactiveIndex ] = binding; - - lastActiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = lastActiveBinding; - - } - - - // Memory management of Interpolants for weight and time scale - - _lendControlInterpolant() { - - const interpolants = this._controlInterpolants, - lastActiveIndex = this._nActiveControlInterpolants ++; - - let interpolant = interpolants[ lastActiveIndex ]; - - if ( interpolant === undefined ) { - - interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, this._controlInterpolantsResultBuffer ); - - interpolant.__cacheIndex = lastActiveIndex; - interpolants[ lastActiveIndex ] = interpolant; - - } - - return interpolant; - - } - - _takeBackControlInterpolant( interpolant ) { - - const interpolants = this._controlInterpolants, - prevIndex = interpolant.__cacheIndex, - - firstInactiveIndex = -- this._nActiveControlInterpolants, - - lastActiveInterpolant = interpolants[ firstInactiveIndex ]; - - interpolant.__cacheIndex = firstInactiveIndex; - interpolants[ firstInactiveIndex ] = interpolant; - - lastActiveInterpolant.__cacheIndex = prevIndex; - interpolants[ prevIndex ] = lastActiveInterpolant; - - } - - // return an action for a clip optionally using a custom root target - // object (this method allocates a lot of dynamic memory in case a - // previously unknown clip/root combination is specified) - clipAction( clip, optionalRoot, blendMode ) { - - const root = optionalRoot || this._root, - rootUuid = root.uuid; - - let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; - - const clipUuid = clipObject !== null ? clipObject.uuid : clip; - - const actionsForClip = this._actionsByClip[ clipUuid ]; - let prototypeAction = null; - - if ( blendMode === undefined ) { - - if ( clipObject !== null ) { - - blendMode = clipObject.blendMode; - - } else { - - blendMode = NormalAnimationBlendMode; - - } - - } - - if ( actionsForClip !== undefined ) { - - const existingAction = actionsForClip.actionByRoot[ rootUuid ]; - - if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { - - return existingAction; - - } - - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; - - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; - - } - - // clip must be known when specified via string - if ( clipObject === null ) return null; - - // allocate all resources required to run it - const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); - - this._bindAction( newAction, prototypeAction ); - - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); - - return newAction; - - } - - // get an existing action - existingAction( clip, optionalRoot ) { - - const root = optionalRoot || this._root, - rootUuid = root.uuid, - - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, - - clipUuid = clipObject ? clipObject.uuid : clip, - - actionsForClip = this._actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - return actionsForClip.actionByRoot[ rootUuid ] || null; - - } - - return null; - - } - - // deactivates all previously scheduled actions - stopAllAction() { - - const actions = this._actions, - nActions = this._nActiveActions; - - for ( let i = nActions - 1; i >= 0; -- i ) { - - actions[ i ].stop(); - - } - - return this; - - } - - // advance the time and update apply the animation - update( deltaTime ) { - - deltaTime *= this.timeScale; - - const actions = this._actions, - nActions = this._nActiveActions, - - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), - - accuIndex = this._accuIndex ^= 1; - - // run active actions - - for ( let i = 0; i !== nActions; ++ i ) { - - const action = actions[ i ]; - - action._update( time, deltaTime, timeDirection, accuIndex ); - - } - - // update scene graph - - const bindings = this._bindings, - nBindings = this._nActiveBindings; - - for ( let i = 0; i !== nBindings; ++ i ) { - - bindings[ i ].apply( accuIndex ); - - } - - return this; - - } - - // Allows you to seek to a specific time in an animation. - setTime( timeInSeconds ) { - - this.time = 0; // Zero out time attribute for AnimationMixer object; - for ( let i = 0; i < this._actions.length; i ++ ) { - - this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. - - } - - return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. - - } - - // return this mixer's root target object - getRoot() { - - return this._root; - - } - - // free all resources specific to a particular clip - uncacheClip( clip ) { - - const actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; - - if ( actionsForClip !== undefined ) { - - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away - - const actionsToRemove = actionsForClip.knownActions; - - for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - - const action = actionsToRemove[ i ]; - - this._deactivateAction( action ); - - const cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; - - action._cacheIndex = null; - action._byClipCacheIndex = null; - - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); - - this._removeInactiveBindingsForAction( action ); - - } - - delete actionsByClip[ clipUuid ]; - - } - - } - - // free all resources specific to a particular root target object - uncacheRoot( root ) { - - const rootUuid = root.uuid, - actionsByClip = this._actionsByClip; - - for ( const clipUuid in actionsByClip ) { - - const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; - - if ( action !== undefined ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - - const bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; - - if ( bindingByName !== undefined ) { - - for ( const trackName in bindingByName ) { - - const binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); - - } - - } - - } - - // remove a targeted clip from the cache - uncacheAction( clip, optionalRoot ) { - - const action = this.existingAction( clip, optionalRoot ); - - if ( action !== null ) { - - this._deactivateAction( action ); - this._removeInactiveAction( action ); - - } - - } - - } - - AnimationMixer.prototype._controlInterpolantsResultBuffer = new Float32Array( 1 ); - - class Uniform { - - constructor( value ) { - - if ( typeof value === 'string' ) { - - console.warn( 'THREE.Uniform: Type parameter is no longer needed.' ); - value = arguments[ 1 ]; - - } - - this.value = value; - - } - - clone() { - - return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); - - } - - } - - class InstancedInterleavedBuffer extends InterleavedBuffer { - - constructor( array, stride, meshPerAttribute = 1 ) { - - super( array, stride ); - - this.meshPerAttribute = meshPerAttribute; - - } - - copy( source ) { - - super.copy( source ); - - this.meshPerAttribute = source.meshPerAttribute; - - return this; - - } - - clone( data ) { - - const ib = super.clone( data ); - - ib.meshPerAttribute = this.meshPerAttribute; - - return ib; - - } - - toJSON( data ) { - - const json = super.toJSON( data ); - - json.isInstancedInterleavedBuffer = true; - json.meshPerAttribute = this.meshPerAttribute; - - return json; - - } - - } - - InstancedInterleavedBuffer.prototype.isInstancedInterleavedBuffer = true; - - class GLBufferAttribute { - - constructor( buffer, type, itemSize, elementSize, count ) { - - this.buffer = buffer; - this.type = type; - this.itemSize = itemSize; - this.elementSize = elementSize; - this.count = count; - - this.version = 0; - - } - - set needsUpdate( value ) { - - if ( value === true ) this.version ++; - - } - - setBuffer( buffer ) { - - this.buffer = buffer; - - return this; - - } - - setType( type, elementSize ) { - - this.type = type; - this.elementSize = elementSize; - - return this; - - } - - setItemSize( itemSize ) { - - this.itemSize = itemSize; - - return this; - - } - - setCount( count ) { - - this.count = count; - - return this; - - } - - } - - GLBufferAttribute.prototype.isGLBufferAttribute = true; - - class Raycaster { - - constructor( origin, direction, near = 0, far = Infinity ) { - - this.ray = new Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) - - this.near = near; - this.far = far; - this.camera = null; - this.layers = new Layers(); - - this.params = { - Mesh: {}, - Line: { threshold: 1 }, - LOD: {}, - Points: { threshold: 1 }, - Sprite: {} - }; - - } - - set( origin, direction ) { - - // direction is assumed to be normalized (for accurate distance calculations) - - this.ray.set( origin, direction ); - - } - - setFromCamera( coords, camera ) { - - if ( camera && camera.isPerspectiveCamera ) { - - this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); - this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); - this.camera = camera; - - } else if ( camera && camera.isOrthographicCamera ) { - - this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera - this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); - this.camera = camera; - - } else { - - console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); - - } - - } - - intersectObject( object, recursive = false, intersects = [] ) { - - intersectObject( object, this, intersects, recursive ); - - intersects.sort( ascSort ); - - return intersects; - - } - - intersectObjects( objects, recursive = false, intersects = [] ) { - - for ( let i = 0, l = objects.length; i < l; i ++ ) { - - intersectObject( objects[ i ], this, intersects, recursive ); - - } - - intersects.sort( ascSort ); - - return intersects; - - } - - } - - function ascSort( a, b ) { - - return a.distance - b.distance; - - } - - function intersectObject( object, raycaster, intersects, recursive ) { - - if ( object.layers.test( raycaster.layers ) ) { - - object.raycast( raycaster, intersects ); - - } - - if ( recursive === true ) { - - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { - - intersectObject( children[ i ], raycaster, intersects, true ); - - } - - } - - } - - /** - * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system - * - * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up. - * The azimuthal angle (theta) is measured from the positive z-axis. - */ - - class Spherical { - - constructor( radius = 1, phi = 0, theta = 0 ) { - - this.radius = radius; - this.phi = phi; // polar angle - this.theta = theta; // azimuthal angle - - return this; - - } - - set( radius, phi, theta ) { - - this.radius = radius; - this.phi = phi; - this.theta = theta; - - return this; - - } - - copy( other ) { - - this.radius = other.radius; - this.phi = other.phi; - this.theta = other.theta; - - return this; - - } - - // restrict phi to be betwee EPS and PI-EPS - makeSafe() { - - const EPS = 0.000001; - this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); - - return this; - - } - - setFromVector3( v ) { - - return this.setFromCartesianCoords( v.x, v.y, v.z ); - - } - - setFromCartesianCoords( x, y, z ) { - - this.radius = Math.sqrt( x * x + y * y + z * z ); - - if ( this.radius === 0 ) { - - this.theta = 0; - this.phi = 0; - - } else { - - this.theta = Math.atan2( x, z ); - this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) ); - - } - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - } - - /** - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system - */ - - class Cylindrical { - - constructor( radius = 1, theta = 0, y = 0 ) { - - this.radius = radius; // distance from the origin to a point in the x-z plane - this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis - this.y = y; // height above the x-z plane - - return this; - - } - - set( radius, theta, y ) { - - this.radius = radius; - this.theta = theta; - this.y = y; - - return this; - - } - - copy( other ) { - - this.radius = other.radius; - this.theta = other.theta; - this.y = other.y; - - return this; - - } - - setFromVector3( v ) { - - return this.setFromCartesianCoords( v.x, v.y, v.z ); - - } - - setFromCartesianCoords( x, y, z ) { - - this.radius = Math.sqrt( x * x + z * z ); - this.theta = Math.atan2( x, z ); - this.y = y; - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - } - - const _vector$4 = /*@__PURE__*/ new Vector2(); - - class Box2 { - - constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { - - this.min = min; - this.max = max; - - } - - set( min, max ) { - - this.min.copy( min ); - this.max.copy( max ); - - return this; - - } - - setFromPoints( points ) { - - this.makeEmpty(); - - for ( let i = 0, il = points.length; i < il; i ++ ) { - - this.expandByPoint( points[ i ] ); - - } - - return this; - - } - - setFromCenterAndSize( center, size ) { - - const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); - - return this; - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - copy( box ) { - - this.min.copy( box.min ); - this.max.copy( box.max ); - - return this; - - } - - makeEmpty() { - - this.min.x = this.min.y = + Infinity; - this.max.x = this.max.y = - Infinity; - - return this; - - } - - isEmpty() { - - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - - } - - getCenter( target ) { - - return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); - - } - - getSize( target ) { - - return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); - - } - - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); - - return this; - - } - - expandByVector( vector ) { - - this.min.sub( vector ); - this.max.add( vector ); - - return this; - - } - - expandByScalar( scalar ) { - - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); - - return this; - - } - - containsPoint( point ) { - - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ? false : true; - - } - - containsBox( box ) { - - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y; - - } - - getParameter( point, target ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - return target.set( - ( point.x - this.min.x ) / ( this.max.x - this.min.x ), - ( point.y - this.min.y ) / ( this.max.y - this.min.y ) - ); - - } - - intersectsBox( box ) { - - // using 4 splitting planes to rule out intersections - - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y ? false : true; - - } - - clampPoint( point, target ) { - - return target.copy( point ).clamp( this.min, this.max ); - - } - - distanceToPoint( point ) { - - const clampedPoint = _vector$4.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); - - } - - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); - - return this; - - } - - union( box ) { - - this.min.min( box.min ); - this.max.max( box.max ); - - return this; - - } - - translate( offset ) { - - this.min.add( offset ); - this.max.add( offset ); - - return this; - - } - - equals( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - - } - - Box2.prototype.isBox2 = true; - - const _startP = /*@__PURE__*/ new Vector3(); - const _startEnd = /*@__PURE__*/ new Vector3(); - - class Line3 { - - constructor( start = new Vector3(), end = new Vector3() ) { - - this.start = start; - this.end = end; - - } - - set( start, end ) { - - this.start.copy( start ); - this.end.copy( end ); - - return this; - - } - - copy( line ) { - - this.start.copy( line.start ); - this.end.copy( line.end ); - - return this; - - } - - getCenter( target ) { - - return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - - } - - delta( target ) { - - return target.subVectors( this.end, this.start ); - - } - - distanceSq() { - - return this.start.distanceToSquared( this.end ); - - } - - distance() { - - return this.start.distanceTo( this.end ); - - } - - at( t, target ) { - - return this.delta( target ).multiplyScalar( t ).add( this.start ); - - } - - closestPointToPointParameter( point, clampToLine ) { - - _startP.subVectors( point, this.start ); - _startEnd.subVectors( this.end, this.start ); - - const startEnd2 = _startEnd.dot( _startEnd ); - const startEnd_startP = _startEnd.dot( _startP ); - - let t = startEnd_startP / startEnd2; - - if ( clampToLine ) { - - t = clamp( t, 0, 1 ); - - } - - return t; - - } - - closestPointToPoint( point, clampToLine, target ) { - - const t = this.closestPointToPointParameter( point, clampToLine ); - - return this.delta( target ).multiplyScalar( t ).add( this.start ); - - } - - applyMatrix4( matrix ) { - - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); - - return this; - - } - - equals( line ) { - - return line.start.equals( this.start ) && line.end.equals( this.end ); - - } - - clone() { - - return new this.constructor().copy( this ); - - } - - } - - class ImmediateRenderObject extends Object3D { - - constructor( material ) { - - super(); - - this.material = material; - this.render = function ( /* renderCallback */ ) {}; - - this.hasPositions = false; - this.hasNormals = false; - this.hasColors = false; - this.hasUvs = false; - - this.positionArray = null; - this.normalArray = null; - this.colorArray = null; - this.uvArray = null; - - this.count = 0; - - } - - } - - ImmediateRenderObject.prototype.isImmediateRenderObject = true; - - const _vector$3 = /*@__PURE__*/ new Vector3(); - - class SpotLightHelper extends Object3D { - - constructor( light, color ) { - - super(); - this.light = light; - this.light.updateMatrixWorld(); - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - const geometry = new BufferGeometry(); - - const positions = [ - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 1, - 0, 0, 0, - 1, 0, 1, - 0, 0, 0, 0, 1, 1, - 0, 0, 0, 0, - 1, 1 - ]; - - for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { - - const p1 = ( i / l ) * Math.PI * 2; - const p2 = ( j / l ) * Math.PI * 2; - - positions.push( - Math.cos( p1 ), Math.sin( p1 ), 1, - Math.cos( p2 ), Math.sin( p2 ), 1 - ); - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - - this.cone = new LineSegments( geometry, material ); - this.add( this.cone ); - - this.update(); - - } - - dispose() { - - this.cone.geometry.dispose(); - this.cone.material.dispose(); - - } - - update() { - - this.light.updateMatrixWorld(); - - const coneLength = this.light.distance ? this.light.distance : 1000; - const coneWidth = coneLength * Math.tan( this.light.angle ); - - this.cone.scale.set( coneWidth, coneWidth, coneLength ); - - _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); - - this.cone.lookAt( _vector$3 ); - - if ( this.color !== undefined ) { - - this.cone.material.color.set( this.color ); - - } else { - - this.cone.material.color.copy( this.light.color ); - - } - - } - - } - - const _vector$2 = /*@__PURE__*/ new Vector3(); - const _boneMatrix = /*@__PURE__*/ new Matrix4(); - const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); - - - class SkeletonHelper extends LineSegments { - - constructor( object ) { - - const bones = getBoneList( object ); - - const geometry = new BufferGeometry(); - - const vertices = []; - const colors = []; - - const color1 = new Color( 0, 0, 1 ); - const color2 = new Color( 0, 1, 0 ); - - for ( let i = 0; i < bones.length; i ++ ) { - - const bone = bones[ i ]; - - if ( bone.parent && bone.parent.isBone ) { - - vertices.push( 0, 0, 0 ); - vertices.push( 0, 0, 0 ); - colors.push( color1.r, color1.g, color1.b ); - colors.push( color2.r, color2.g, color2.b ); - - } - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); - - super( geometry, material ); - - this.type = 'SkeletonHelper'; - this.isSkeletonHelper = true; - - this.root = object; - this.bones = bones; - - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; - - } - - updateMatrixWorld( force ) { - - const bones = this.bones; - - const geometry = this.geometry; - const position = geometry.getAttribute( 'position' ); - - _matrixWorldInv.copy( this.root.matrixWorld ).invert(); - - for ( let i = 0, j = 0; i < bones.length; i ++ ) { - - const bone = bones[ i ]; - - if ( bone.parent && bone.parent.isBone ) { - - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); - - _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); - _vector$2.setFromMatrixPosition( _boneMatrix ); - position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); - - j += 2; - - } - - } - - geometry.getAttribute( 'position' ).needsUpdate = true; - - super.updateMatrixWorld( force ); - - } - - } - - - function getBoneList( object ) { - - const boneList = []; - - if ( object && object.isBone ) { - - boneList.push( object ); - - } - - for ( let i = 0; i < object.children.length; i ++ ) { - - boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); - - } - - return boneList; - - } - - class PointLightHelper extends Mesh { - - constructor( light, sphereSize, color ) { - - const geometry = new SphereGeometry( sphereSize, 4, 2 ); - const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - - super( geometry, material ); - - this.light = light; - this.light.updateMatrixWorld(); - - this.color = color; - - this.type = 'PointLightHelper'; - - this.matrix = this.light.matrixWorld; - this.matrixAutoUpdate = false; - - this.update(); - - - /* - // TODO: delete this comment? - const distanceGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 ); - const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - - const d = light.distance; - - if ( d === 0.0 ) { - - this.lightDistance.visible = false; - - } else { - - this.lightDistance.scale.set( d, d, d ); - - } - - this.add( this.lightDistance ); - */ - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - - update() { - - if ( this.color !== undefined ) { - - this.material.color.set( this.color ); - - } else { - - this.material.color.copy( this.light.color ); - - } - - /* - const d = this.light.distance; - - if ( d === 0.0 ) { - - this.lightDistance.visible = false; - - } else { - - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); - - } - */ - - } - - } - - const _vector$1 = /*@__PURE__*/ new Vector3(); - const _color1 = /*@__PURE__*/ new Color(); - const _color2 = /*@__PURE__*/ new Color(); - - class HemisphereLightHelper extends Object3D { - - constructor( light, size, color ) { - - super(); - this.light = light; - this.light.updateMatrixWorld(); - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - const geometry = new OctahedronGeometry( size ); - geometry.rotateY( Math.PI * 0.5 ); - - this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - if ( this.color === undefined ) this.material.vertexColors = true; - - const position = geometry.getAttribute( 'position' ); - const colors = new Float32Array( position.count * 3 ); - - geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); - - this.add( new Mesh( geometry, this.material ) ); - - this.update(); - - } - - dispose() { - - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); - - } - - update() { - - const mesh = this.children[ 0 ]; - - if ( this.color !== undefined ) { - - this.material.color.set( this.color ); - - } else { - - const colors = mesh.geometry.getAttribute( 'color' ); - - _color1.copy( this.light.color ); - _color2.copy( this.light.groundColor ); - - for ( let i = 0, l = colors.count; i < l; i ++ ) { - - const color = ( i < ( l / 2 ) ) ? _color1 : _color2; - - colors.setXYZ( i, color.r, color.g, color.b ); - - } - - colors.needsUpdate = true; - - } - - mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); - - } - - } - - class GridHelper extends LineSegments { - - constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { - - color1 = new Color( color1 ); - color2 = new Color( color2 ); - - const center = divisions / 2; - const step = size / divisions; - const halfSize = size / 2; - - const vertices = [], colors = []; - - for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { - - vertices.push( - halfSize, 0, k, halfSize, 0, k ); - vertices.push( k, 0, - halfSize, k, 0, halfSize ); - - const color = i === center ? color1 : color2; - - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - - } - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'GridHelper'; - - } - - } - - class PolarGridHelper extends LineSegments { - - constructor( radius = 10, radials = 16, circles = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { - - color1 = new Color( color1 ); - color2 = new Color( color2 ); - - const vertices = []; - const colors = []; - - // create the radials - - for ( let i = 0; i <= radials; i ++ ) { - - const v = ( i / radials ) * ( Math.PI * 2 ); - - const x = Math.sin( v ) * radius; - const z = Math.cos( v ) * radius; - - vertices.push( 0, 0, 0 ); - vertices.push( x, 0, z ); - - const color = ( i & 1 ) ? color1 : color2; - - colors.push( color.r, color.g, color.b ); - colors.push( color.r, color.g, color.b ); - - } - - // create the circles - - for ( let i = 0; i <= circles; i ++ ) { - - const color = ( i & 1 ) ? color1 : color2; - - const r = radius - ( radius / circles * i ); - - for ( let j = 0; j < divisions; j ++ ) { - - // first vertex - - let v = ( j / divisions ) * ( Math.PI * 2 ); - - let x = Math.sin( v ) * r; - let z = Math.cos( v ) * r; - - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); - - // second vertex - - v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); - - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; - - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); - - } - - } - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'PolarGridHelper'; - - } - - } - - const _v1 = /*@__PURE__*/ new Vector3(); - const _v2 = /*@__PURE__*/ new Vector3(); - const _v3 = /*@__PURE__*/ new Vector3(); - - class DirectionalLightHelper extends Object3D { - - constructor( light, size, color ) { - - super(); - this.light = light; - this.light.updateMatrixWorld(); - - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; - - this.color = color; - - if ( size === undefined ) size = 1; - - let geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ - - size, size, 0, - size, size, 0, - size, - size, 0, - - size, - size, 0, - - size, size, 0 - ], 3 ) ); - - const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - - this.lightPlane = new Line( geometry, material ); - this.add( this.lightPlane ); - - geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); - - this.targetLine = new Line( geometry, material ); - this.add( this.targetLine ); - - this.update(); - - } - - dispose() { - - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); - - } - - update() { - - _v1.setFromMatrixPosition( this.light.matrixWorld ); - _v2.setFromMatrixPosition( this.light.target.matrixWorld ); - _v3.subVectors( _v2, _v1 ); - - this.lightPlane.lookAt( _v2 ); - - if ( this.color !== undefined ) { - - this.lightPlane.material.color.set( this.color ); - this.targetLine.material.color.set( this.color ); - - } else { - - this.lightPlane.material.color.copy( this.light.color ); - this.targetLine.material.color.copy( this.light.color ); - - } - - this.targetLine.lookAt( _v2 ); - this.targetLine.scale.z = _v3.length(); - - } - - } - - const _vector = /*@__PURE__*/ new Vector3(); - const _camera = /*@__PURE__*/ new Camera(); - - /** - * - shows frustum, line of sight and up of the camera - * - suitable for fast updates - * - based on frustum visualization in lightgl.js shadowmap example - * http://evanw.github.com/lightgl.js/tests/shadowmap.html - */ - - class CameraHelper extends LineSegments { - - constructor( camera ) { - - const geometry = new BufferGeometry(); - const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); - - const vertices = []; - const colors = []; - - const pointMap = {}; - - // colors - - const colorFrustum = new Color( 0xffaa00 ); - const colorCone = new Color( 0xff0000 ); - const colorUp = new Color( 0x00aaff ); - const colorTarget = new Color( 0xffffff ); - const colorCross = new Color( 0x333333 ); - - // near - - addLine( 'n1', 'n2', colorFrustum ); - addLine( 'n2', 'n4', colorFrustum ); - addLine( 'n4', 'n3', colorFrustum ); - addLine( 'n3', 'n1', colorFrustum ); - - // far - - addLine( 'f1', 'f2', colorFrustum ); - addLine( 'f2', 'f4', colorFrustum ); - addLine( 'f4', 'f3', colorFrustum ); - addLine( 'f3', 'f1', colorFrustum ); - - // sides - - addLine( 'n1', 'f1', colorFrustum ); - addLine( 'n2', 'f2', colorFrustum ); - addLine( 'n3', 'f3', colorFrustum ); - addLine( 'n4', 'f4', colorFrustum ); - - // cone - - addLine( 'p', 'n1', colorCone ); - addLine( 'p', 'n2', colorCone ); - addLine( 'p', 'n3', colorCone ); - addLine( 'p', 'n4', colorCone ); - - // up - - addLine( 'u1', 'u2', colorUp ); - addLine( 'u2', 'u3', colorUp ); - addLine( 'u3', 'u1', colorUp ); - - // target - - addLine( 'c', 't', colorTarget ); - addLine( 'p', 'c', colorCross ); - - // cross - - addLine( 'cn1', 'cn2', colorCross ); - addLine( 'cn3', 'cn4', colorCross ); - - addLine( 'cf1', 'cf2', colorCross ); - addLine( 'cf3', 'cf4', colorCross ); - - function addLine( a, b, color ) { - - addPoint( a, color ); - addPoint( b, color ); - - } - - function addPoint( id, color ) { - - vertices.push( 0, 0, 0 ); - colors.push( color.r, color.g, color.b ); - - if ( pointMap[ id ] === undefined ) { - - pointMap[ id ] = []; - - } - - pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); - - } - - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - super( geometry, material ); - - this.type = 'CameraHelper'; - - this.camera = camera; - if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); - - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; - - this.pointMap = pointMap; - - this.update(); - - } - - update() { - - const geometry = this.geometry; - const pointMap = this.pointMap; - - const w = 1, h = 1; - - // we need just camera projection matrix inverse - // world matrix must be identity - - _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); - - // center / target - - setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); - setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); - - // near - - setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); - setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); - setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); - setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); - - // far - - setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 ); - setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 ); - setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 ); - setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 ); - - // up - - setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); - - // cross - - setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 ); - setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 ); - setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); - setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); - - setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); - setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); - setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); - setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); - - geometry.getAttribute( 'position' ).needsUpdate = true; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - - } - - - function setPoint( point, pointMap, geometry, camera, x, y, z ) { - - _vector.set( x, y, z ).unproject( camera ); - - const points = pointMap[ point ]; - - if ( points !== undefined ) { - - const position = geometry.getAttribute( 'position' ); - - for ( let i = 0, l = points.length; i < l; i ++ ) { - - position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); - - } - - } - - } - - const _box = /*@__PURE__*/ new Box3(); - - class BoxHelper extends LineSegments { - - constructor( object, color = 0xffff00 ) { - - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - const positions = new Float32Array( 8 * 3 ); - - const geometry = new BufferGeometry(); - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.object = object; - this.type = 'BoxHelper'; - - this.matrixAutoUpdate = false; - - this.update(); - - } - - update( object ) { - - if ( object !== undefined ) { - - console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); - - } - - if ( this.object !== undefined ) { - - _box.setFromObject( this.object ); - - } - - if ( _box.isEmpty() ) return; - - const min = _box.min; - const max = _box.max; - - /* - 5____4 - 1/___0/| - | 6__|_7 - 2/___3/ - - 0: max.x, max.y, max.z - 1: min.x, max.y, max.z - 2: min.x, min.y, max.z - 3: max.x, min.y, max.z - 4: max.x, max.y, min.z - 5: min.x, max.y, min.z - 6: min.x, min.y, min.z - 7: max.x, min.y, min.z - */ - - const position = this.geometry.attributes.position; - const array = position.array; - - array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; - array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; - array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; - array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; - array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; - array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; - array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; - array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; - - position.needsUpdate = true; - - this.geometry.computeBoundingSphere(); - - - } - - setFromObject( object ) { - - this.object = object; - this.update(); - - return this; - - } - - copy( source ) { - - LineSegments.prototype.copy.call( this, source ); - - this.object = source.object; - - return this; - - } - - } - - class Box3Helper extends LineSegments { - - constructor( box, color = 0xffff00 ) { - - const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - - const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; - - const geometry = new BufferGeometry(); - - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.box = box; - - this.type = 'Box3Helper'; - - this.geometry.computeBoundingSphere(); - - } - - updateMatrixWorld( force ) { - - const box = this.box; - - if ( box.isEmpty() ) return; - - box.getCenter( this.position ); - - box.getSize( this.scale ); - - this.scale.multiplyScalar( 0.5 ); - - super.updateMatrixWorld( force ); - - } - - } - - class PlaneHelper extends Line { - - constructor( plane, size = 1, hex = 0xffff00 ) { - - const color = hex; - - const positions = [ 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, 0, 1, 0, 0, 0 ]; - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - geometry.computeBoundingSphere(); - - super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - - this.type = 'PlaneHelper'; - - this.plane = plane; - - this.size = size; - - const positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ]; - - const geometry2 = new BufferGeometry(); - geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); - geometry2.computeBoundingSphere(); - - this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); - - } - - updateMatrixWorld( force ) { - - let scale = - this.plane.constant; - - if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter - - this.scale.set( 0.5 * this.size, 0.5 * this.size, scale ); - - this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here - - this.lookAt( this.plane.normal ); - - super.updateMatrixWorld( force ); - - } - - } - - const _axis = /*@__PURE__*/ new Vector3(); - let _lineGeometry, _coneGeometry; - - class ArrowHelper extends Object3D { - - // dir is assumed to be normalized - - constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { - - super(); - - this.type = 'ArrowHelper'; - - if ( _lineGeometry === undefined ) { - - _lineGeometry = new BufferGeometry(); - _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); - - _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); - _coneGeometry.translate( 0, - 0.5, 0 ); - - } - - this.position.copy( origin ); - - this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); - - this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); - - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); - - } - - setDirection( dir ) { - - // dir is assumed to be normalized - - if ( dir.y > 0.99999 ) { - - this.quaternion.set( 0, 0, 0, 1 ); - - } else if ( dir.y < - 0.99999 ) { - - this.quaternion.set( 1, 0, 0, 0 ); - - } else { - - _axis.set( dir.z, 0, - dir.x ).normalize(); - - const radians = Math.acos( dir.y ); - - this.quaternion.setFromAxisAngle( _axis, radians ); - - } - - } - - setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { - - this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 - this.line.updateMatrix(); - - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); - - } - - setColor( color ) { - - this.line.material.color.set( color ); - this.cone.material.color.set( color ); - - } - - copy( source ) { - - super.copy( source, false ); - - this.line.copy( source.line ); - this.cone.copy( source.cone ); - - return this; - - } - - } - - class AxesHelper extends LineSegments { - - constructor( size = 1 ) { - - const vertices = [ - 0, 0, 0, size, 0, 0, - 0, 0, 0, 0, size, 0, - 0, 0, 0, 0, 0, size - ]; - - const colors = [ - 1, 0, 0, 1, 0.6, 0, - 0, 1, 0, 0.6, 1, 0, - 0, 0, 1, 0, 0.6, 1 - ]; - - const geometry = new BufferGeometry(); - geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - - const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - - super( geometry, material ); - - this.type = 'AxesHelper'; - - } - - setColors( xAxisColor, yAxisColor, zAxisColor ) { - - const color = new Color(); - const array = this.geometry.attributes.color.array; - - color.set( xAxisColor ); - color.toArray( array, 0 ); - color.toArray( array, 3 ); - - color.set( yAxisColor ); - color.toArray( array, 6 ); - color.toArray( array, 9 ); - - color.set( zAxisColor ); - color.toArray( array, 12 ); - color.toArray( array, 15 ); - - this.geometry.attributes.color.needsUpdate = true; - - return this; - - } - - dispose() { - - this.geometry.dispose(); - this.material.dispose(); - - } - - } - - const _floatView = new Float32Array( 1 ); - const _int32View = new Int32Array( _floatView.buffer ); - - class DataUtils { - - // Converts float32 to float16 (stored as uint16 value). - - static toHalfFloat( val ) { - - // Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410 - - /* This method is faster than the OpenEXR implementation (very often - * used, eg. in Ogre), with the additional benefit of rounding, inspired - * by James Tursa?s half-precision code. */ - - _floatView[ 0 ] = val; - const x = _int32View[ 0 ]; - - let bits = ( x >> 16 ) & 0x8000; /* Get the sign */ - let m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */ - const e = ( x >> 23 ) & 0xff; /* Using int is faster here */ - - /* If zero, or denormal, or exponent underflows too much for a denormal - * half, return signed zero. */ - if ( e < 103 ) return bits; - - /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */ - if ( e > 142 ) { - - bits |= 0x7c00; - /* If exponent was 0xff and one mantissa bit was set, it means NaN, - * not Inf, so make sure we set one mantissa bit too. */ - bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff ); - return bits; - - } - - /* If exponent underflows but not too much, return a denormal */ - if ( e < 113 ) { - - m |= 0x0800; - /* Extra rounding may overflow and set mantissa to 0 and exponent - * to 1, which is OK. */ - bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 ); - return bits; - - } - - bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 ); - /* Extra rounding. An overflow will set mantissa to 0 and increment - * the exponent, which is OK. */ - bits += m & 1; - return bits; - - } - - } - - const LineStrip = 0; - const LinePieces = 1; - const NoColors = 0; - const FaceColors = 1; - const VertexColors = 2; - - function MeshFaceMaterial( materials ) { - - console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' ); - return materials; - - } - - function MultiMaterial( materials = [] ) { - - console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' ); - materials.isMultiMaterial = true; - materials.materials = materials; - materials.clone = function () { - - return materials.slice(); - - }; - - return materials; - - } - - function PointCloud( geometry, material ) { - - console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' ); - return new Points( geometry, material ); - - } - - function Particle( material ) { - - console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' ); - return new Sprite( material ); - - } - - function ParticleSystem( geometry, material ) { - - console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' ); - return new Points( geometry, material ); - - } - - function PointCloudMaterial( parameters ) { - - console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); - - } - - function ParticleBasicMaterial( parameters ) { - - console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); - - } - - function ParticleSystemMaterial( parameters ) { - - console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); - - } - - function Vertex( x, y, z ) { - - console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' ); - return new Vector3( x, y, z ); - - } - - // - - function DynamicBufferAttribute( array, itemSize ) { - - console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setUsage( THREE.DynamicDrawUsage ) instead.' ); - return new BufferAttribute( array, itemSize ).setUsage( DynamicDrawUsage ); - - } - - function Int8Attribute( array, itemSize ) { - - console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' ); - return new Int8BufferAttribute( array, itemSize ); - - } - - function Uint8Attribute( array, itemSize ) { - - console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' ); - return new Uint8BufferAttribute( array, itemSize ); - - } - - function Uint8ClampedAttribute( array, itemSize ) { - - console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' ); - return new Uint8ClampedBufferAttribute( array, itemSize ); - - } - - function Int16Attribute( array, itemSize ) { - - console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' ); - return new Int16BufferAttribute( array, itemSize ); - - } - - function Uint16Attribute( array, itemSize ) { - - console.warn( 'THREE.Uint16Attribute has been removed. Use new THREE.Uint16BufferAttribute() instead.' ); - return new Uint16BufferAttribute( array, itemSize ); - - } - - function Int32Attribute( array, itemSize ) { - - console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' ); - return new Int32BufferAttribute( array, itemSize ); - - } - - function Uint32Attribute( array, itemSize ) { - - console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' ); - return new Uint32BufferAttribute( array, itemSize ); - - } - - function Float32Attribute( array, itemSize ) { - - console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' ); - return new Float32BufferAttribute( array, itemSize ); - - } - - function Float64Attribute( array, itemSize ) { - - console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' ); - return new Float64BufferAttribute( array, itemSize ); - - } - - // - - Curve.create = function ( construct, getPoint ) { - - console.log( 'THREE.Curve.create() has been deprecated' ); - - construct.prototype = Object.create( Curve.prototype ); - construct.prototype.constructor = construct; - construct.prototype.getPoint = getPoint; - - return construct; - - }; - - // - - Path.prototype.fromPoints = function ( points ) { - - console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' ); - return this.setFromPoints( points ); - - }; - - // - - function AxisHelper( size ) { - - console.warn( 'THREE.AxisHelper has been renamed to THREE.AxesHelper.' ); - return new AxesHelper( size ); - - } - - function BoundingBoxHelper( object, color ) { - - console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' ); - return new BoxHelper( object, color ); - - } - - function EdgesHelper( object, hex ) { - - console.warn( 'THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead.' ); - return new LineSegments( new EdgesGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) ); - - } - - GridHelper.prototype.setColors = function () { - - console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' ); - - }; - - SkeletonHelper.prototype.update = function () { - - console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' ); - - }; - - function WireframeHelper( object, hex ) { - - console.warn( 'THREE.WireframeHelper has been removed. Use THREE.WireframeGeometry instead.' ); - return new LineSegments( new WireframeGeometry( object.geometry ), new LineBasicMaterial( { color: hex !== undefined ? hex : 0xffffff } ) ); - - } - - // - - Loader.prototype.extractUrlBase = function ( url ) { - - console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' ); - return LoaderUtils.extractUrlBase( url ); - - }; - - Loader.Handlers = { - - add: function ( /* regex, loader */ ) { - - console.error( 'THREE.Loader: Handlers.add() has been removed. Use LoadingManager.addHandler() instead.' ); - - }, - - get: function ( /* file */ ) { - - console.error( 'THREE.Loader: Handlers.get() has been removed. Use LoadingManager.getHandler() instead.' ); - - } - - }; - - function XHRLoader( manager ) { - - console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' ); - return new FileLoader( manager ); - - } - - function BinaryTextureLoader( manager ) { - - console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' ); - return new DataTextureLoader( manager ); - - } - - // - - Box2.prototype.center = function ( optionalTarget ) { - - console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); - - }; - - Box2.prototype.empty = function () { - - console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); - - }; - - Box2.prototype.isIntersectionBox = function ( box ) { - - console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); - - }; - - Box2.prototype.size = function ( optionalTarget ) { - - console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' ); - return this.getSize( optionalTarget ); - - }; - - // - - Box3.prototype.center = function ( optionalTarget ) { - - console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); - - }; - - Box3.prototype.empty = function () { - - console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); - - }; - - Box3.prototype.isIntersectionBox = function ( box ) { - - console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); - - }; - - Box3.prototype.isIntersectionSphere = function ( sphere ) { - - console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); - return this.intersectsSphere( sphere ); - - }; - - Box3.prototype.size = function ( optionalTarget ) { - - console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' ); - return this.getSize( optionalTarget ); - - }; - - // - - Sphere.prototype.empty = function () { - - console.warn( 'THREE.Sphere: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); - - }; - - // - - Frustum.prototype.setFromMatrix = function ( m ) { - - console.warn( 'THREE.Frustum: .setFromMatrix() has been renamed to .setFromProjectionMatrix().' ); - return this.setFromProjectionMatrix( m ); - - }; - - // - - Line3.prototype.center = function ( optionalTarget ) { - - console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); - - }; - - // - - Matrix3.prototype.flattenToArrayOffset = function ( array, offset ) { - - console.warn( 'THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' ); - return this.toArray( array, offset ); - - }; - - Matrix3.prototype.multiplyVector3 = function ( vector ) { - - console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); - return vector.applyMatrix3( this ); - - }; - - Matrix3.prototype.multiplyVector3Array = function ( /* a */ ) { - - console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' ); - - }; - - Matrix3.prototype.applyToBufferAttribute = function ( attribute ) { - - console.warn( 'THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead.' ); - return attribute.applyMatrix3( this ); - - }; - - Matrix3.prototype.applyToVector3Array = function ( /* array, offset, length */ ) { - - console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' ); - - }; - - Matrix3.prototype.getInverse = function ( matrix ) { - - console.warn( 'THREE.Matrix3: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' ); - return this.copy( matrix ).invert(); - - }; - - // - - Matrix4.prototype.extractPosition = function ( m ) { - - console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); - return this.copyPosition( m ); - - }; - - Matrix4.prototype.flattenToArrayOffset = function ( array, offset ) { - - console.warn( 'THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead.' ); - return this.toArray( array, offset ); - - }; - - Matrix4.prototype.getPosition = function () { - - console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); - return new Vector3().setFromMatrixColumn( this, 3 ); - - }; - - Matrix4.prototype.setRotationFromQuaternion = function ( q ) { - - console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); - return this.makeRotationFromQuaternion( q ); - - }; - - Matrix4.prototype.multiplyToArray = function () { - - console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' ); - - }; - - Matrix4.prototype.multiplyVector3 = function ( vector ) { - - console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }; - - Matrix4.prototype.multiplyVector4 = function ( vector ) { - - console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }; - - Matrix4.prototype.multiplyVector3Array = function ( /* a */ ) { - - console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' ); - - }; - - Matrix4.prototype.rotateAxis = function ( v ) { - - console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); - v.transformDirection( this ); - - }; - - Matrix4.prototype.crossVector = function ( vector ) { - - console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); - - }; - - Matrix4.prototype.translate = function () { - - console.error( 'THREE.Matrix4: .translate() has been removed.' ); - - }; - - Matrix4.prototype.rotateX = function () { - - console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); - - }; - - Matrix4.prototype.rotateY = function () { - - console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); - - }; - - Matrix4.prototype.rotateZ = function () { - - console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); - - }; - - Matrix4.prototype.rotateByAxis = function () { - - console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); - - }; - - Matrix4.prototype.applyToBufferAttribute = function ( attribute ) { - - console.warn( 'THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead.' ); - return attribute.applyMatrix4( this ); - - }; - - Matrix4.prototype.applyToVector3Array = function ( /* array, offset, length */ ) { - - console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' ); - - }; - - Matrix4.prototype.makeFrustum = function ( left, right, bottom, top, near, far ) { - - console.warn( 'THREE.Matrix4: .makeFrustum() has been removed. Use .makePerspective( left, right, top, bottom, near, far ) instead.' ); - return this.makePerspective( left, right, top, bottom, near, far ); - - }; - - Matrix4.prototype.getInverse = function ( matrix ) { - - console.warn( 'THREE.Matrix4: .getInverse() has been removed. Use matrixInv.copy( matrix ).invert(); instead.' ); - return this.copy( matrix ).invert(); - - }; - - // - - Plane.prototype.isIntersectionLine = function ( line ) { - - console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' ); - return this.intersectsLine( line ); - - }; - - // - - Quaternion.prototype.multiplyVector3 = function ( vector ) { - - console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); - return vector.applyQuaternion( this ); - - }; - - Quaternion.prototype.inverse = function ( ) { - - console.warn( 'THREE.Quaternion: .inverse() has been renamed to invert().' ); - return this.invert(); - - }; - - // - - Ray.prototype.isIntersectionBox = function ( box ) { - - console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); - - }; - - Ray.prototype.isIntersectionPlane = function ( plane ) { - - console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' ); - return this.intersectsPlane( plane ); - - }; - - Ray.prototype.isIntersectionSphere = function ( sphere ) { - - console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); - return this.intersectsSphere( sphere ); - - }; - - // - - Triangle.prototype.area = function () { - - console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' ); - return this.getArea(); - - }; - - Triangle.prototype.barycoordFromPoint = function ( point, target ) { - - console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' ); - return this.getBarycoord( point, target ); - - }; - - Triangle.prototype.midpoint = function ( target ) { - - console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' ); - return this.getMidpoint( target ); - - }; - - Triangle.prototypenormal = function ( target ) { - - console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' ); - return this.getNormal( target ); - - }; - - Triangle.prototype.plane = function ( target ) { - - console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' ); - return this.getPlane( target ); - - }; - - Triangle.barycoordFromPoint = function ( point, a, b, c, target ) { - - console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' ); - return Triangle.getBarycoord( point, a, b, c, target ); - - }; - - Triangle.normal = function ( a, b, c, target ) { - - console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' ); - return Triangle.getNormal( a, b, c, target ); - - }; - - // - - Shape.prototype.extractAllPoints = function ( divisions ) { - - console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' ); - return this.extractPoints( divisions ); - - }; - - Shape.prototype.extrude = function ( options ) { - - console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' ); - return new ExtrudeGeometry( this, options ); - - }; - - Shape.prototype.makeGeometry = function ( options ) { - - console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' ); - return new ShapeGeometry( this, options ); - - }; - - // - - Vector2.prototype.fromAttribute = function ( attribute, index, offset ) { - - console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); - - }; - - Vector2.prototype.distanceToManhattan = function ( v ) { - - console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); - return this.manhattanDistanceTo( v ); - - }; - - Vector2.prototype.lengthManhattan = function () { - - console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); - - }; - - // - - Vector3.prototype.setEulerFromRotationMatrix = function () { - - console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); - - }; - - Vector3.prototype.setEulerFromQuaternion = function () { - - console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); - - }; - - Vector3.prototype.getPositionFromMatrix = function ( m ) { - - console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); - return this.setFromMatrixPosition( m ); - - }; - - Vector3.prototype.getScaleFromMatrix = function ( m ) { - - console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); - return this.setFromMatrixScale( m ); - - }; - - Vector3.prototype.getColumnFromMatrix = function ( index, matrix ) { - - console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); - return this.setFromMatrixColumn( matrix, index ); - - }; - - Vector3.prototype.applyProjection = function ( m ) { - - console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' ); - return this.applyMatrix4( m ); - - }; - - Vector3.prototype.fromAttribute = function ( attribute, index, offset ) { - - console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); - - }; - - Vector3.prototype.distanceToManhattan = function ( v ) { - - console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); - return this.manhattanDistanceTo( v ); - - }; - - Vector3.prototype.lengthManhattan = function () { - - console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); - - }; - - // - - Vector4.prototype.fromAttribute = function ( attribute, index, offset ) { - - console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); - - }; - - Vector4.prototype.lengthManhattan = function () { - - console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); - - }; - - // - - Object3D.prototype.getChildByName = function ( name ) { - - console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name ); - - }; - - Object3D.prototype.renderDepth = function () { - - console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); - - }; - - Object3D.prototype.translate = function ( distance, axis ) { - - console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); - return this.translateOnAxis( axis, distance ); - - }; - - Object3D.prototype.getWorldRotation = function () { - - console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' ); - - }; - - Object3D.prototype.applyMatrix = function ( matrix ) { - - console.warn( 'THREE.Object3D: .applyMatrix() has been renamed to .applyMatrix4().' ); - return this.applyMatrix4( matrix ); - - }; - - Object.defineProperties( Object3D.prototype, { - - eulerOrder: { - get: function () { - - console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); - return this.rotation.order; - - }, - set: function ( value ) { - - console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); - this.rotation.order = value; - - } - }, - useQuaternion: { - get: function () { - - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - - }, - set: function () { - - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); - - } - } - - } ); - - Mesh.prototype.setDrawMode = function () { - - console.error( 'THREE.Mesh: .setDrawMode() has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' ); - - }; - - Object.defineProperties( Mesh.prototype, { - - drawMode: { - get: function () { - - console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode.' ); - return TrianglesDrawMode; - - }, - set: function () { - - console.error( 'THREE.Mesh: .drawMode has been removed. The renderer now always assumes THREE.TrianglesDrawMode. Transform your geometry via BufferGeometryUtils.toTrianglesDrawMode() if necessary.' ); - - } - } - - } ); - - SkinnedMesh.prototype.initBones = function () { - - console.error( 'THREE.SkinnedMesh: initBones() has been removed.' ); - - }; - - // - - PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) { - - console.warn( 'THREE.PerspectiveCamera.setLens is deprecated. ' + - 'Use .setFocalLength and .filmGauge for a photographic setup.' ); - - if ( filmGauge !== undefined ) this.filmGauge = filmGauge; - this.setFocalLength( focalLength ); - - }; - - // - - Object.defineProperties( Light.prototype, { - onlyShadow: { - set: function () { - - console.warn( 'THREE.Light: .onlyShadow has been removed.' ); - - } - }, - shadowCameraFov: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' ); - this.shadow.camera.fov = value; - - } - }, - shadowCameraLeft: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' ); - this.shadow.camera.left = value; - - } - }, - shadowCameraRight: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' ); - this.shadow.camera.right = value; - - } - }, - shadowCameraTop: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' ); - this.shadow.camera.top = value; - - } - }, - shadowCameraBottom: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' ); - this.shadow.camera.bottom = value; - - } - }, - shadowCameraNear: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' ); - this.shadow.camera.near = value; - - } - }, - shadowCameraFar: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' ); - this.shadow.camera.far = value; - - } - }, - shadowCameraVisible: { - set: function () { - - console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' ); - - } - }, - shadowBias: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' ); - this.shadow.bias = value; - - } - }, - shadowDarkness: { - set: function () { - - console.warn( 'THREE.Light: .shadowDarkness has been removed.' ); - - } - }, - shadowMapWidth: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' ); - this.shadow.mapSize.width = value; - - } - }, - shadowMapHeight: { - set: function ( value ) { - - console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' ); - this.shadow.mapSize.height = value; - - } - } - } ); - - // - - Object.defineProperties( BufferAttribute.prototype, { - - length: { - get: function () { - - console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' ); - return this.array.length; - - } - }, - dynamic: { - get: function () { - - console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' ); - return this.usage === DynamicDrawUsage; - - }, - set: function ( /* value */ ) { - - console.warn( 'THREE.BufferAttribute: .dynamic has been deprecated. Use .usage instead.' ); - this.setUsage( DynamicDrawUsage ); - - } - } - - } ); - - BufferAttribute.prototype.setDynamic = function ( value ) { - - console.warn( 'THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead.' ); - this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage ); - return this; - - }; - - BufferAttribute.prototype.copyIndicesArray = function ( /* indices */ ) { - - console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' ); - - }, - - BufferAttribute.prototype.setArray = function ( /* array */ ) { - - console.error( 'THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' ); - - }; - - // - - BufferGeometry.prototype.addIndex = function ( index ) { - - console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); - this.setIndex( index ); - - }; - - BufferGeometry.prototype.addAttribute = function ( name, attribute ) { - - console.warn( 'THREE.BufferGeometry: .addAttribute() has been renamed to .setAttribute().' ); - - if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) { - - console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); - - return this.setAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); - - } - - if ( name === 'index' ) { - - console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); - this.setIndex( attribute ); - - return this; - - } - - return this.setAttribute( name, attribute ); - - }; - - BufferGeometry.prototype.addDrawCall = function ( start, count, indexOffset ) { - - if ( indexOffset !== undefined ) { - - console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); - - } - - console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); - this.addGroup( start, count ); - - }; - - BufferGeometry.prototype.clearDrawCalls = function () { - - console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); - this.clearGroups(); - - }; - - BufferGeometry.prototype.computeOffsets = function () { - - console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' ); - - }; - - BufferGeometry.prototype.removeAttribute = function ( name ) { - - console.warn( 'THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute().' ); - - return this.deleteAttribute( name ); - - }; - - BufferGeometry.prototype.applyMatrix = function ( matrix ) { - - console.warn( 'THREE.BufferGeometry: .applyMatrix() has been renamed to .applyMatrix4().' ); - return this.applyMatrix4( matrix ); - - }; - - Object.defineProperties( BufferGeometry.prototype, { - - drawcalls: { - get: function () { - - console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' ); - return this.groups; - - } - }, - offsets: { - get: function () { - - console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' ); - return this.groups; - - } - } - - } ); - - InterleavedBuffer.prototype.setDynamic = function ( value ) { - - console.warn( 'THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead.' ); - this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage ); - return this; - - }; - - InterleavedBuffer.prototype.setArray = function ( /* array */ ) { - - console.error( 'THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' ); - - }; - - // - - ExtrudeGeometry.prototype.getArrays = function () { - - console.error( 'THREE.ExtrudeGeometry: .getArrays() has been removed.' ); - - }; - - ExtrudeGeometry.prototype.addShapeList = function () { - - console.error( 'THREE.ExtrudeGeometry: .addShapeList() has been removed.' ); - - }; - - ExtrudeGeometry.prototype.addShape = function () { - - console.error( 'THREE.ExtrudeGeometry: .addShape() has been removed.' ); - - }; - - // - - Scene.prototype.dispose = function () { - - console.error( 'THREE.Scene: .dispose() has been removed.' ); - - }; - - // - - Uniform.prototype.onUpdate = function () { - - console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' ); - return this; - - }; - - // - - Object.defineProperties( Material.prototype, { - - wrapAround: { - get: function () { - - console.warn( 'THREE.Material: .wrapAround has been removed.' ); - - }, - set: function () { - - console.warn( 'THREE.Material: .wrapAround has been removed.' ); - - } - }, - - overdraw: { - get: function () { - - console.warn( 'THREE.Material: .overdraw has been removed.' ); - - }, - set: function () { - - console.warn( 'THREE.Material: .overdraw has been removed.' ); - - } - }, - - wrapRGB: { - get: function () { - - console.warn( 'THREE.Material: .wrapRGB has been removed.' ); - return new Color(); - - } - }, - - shading: { - get: function () { - - console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); - - }, - set: function ( value ) { - - console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); - this.flatShading = ( value === FlatShading ); - - } - }, - - stencilMask: { - get: function () { - - console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' ); - return this.stencilFuncMask; - - }, - set: function ( value ) { - - console.warn( 'THREE.' + this.type + ': .stencilMask has been removed. Use .stencilFuncMask instead.' ); - this.stencilFuncMask = value; - - } - }, - - vertexTangents: { - get: function () { - - console.warn( 'THREE.' + this.type + ': .vertexTangents has been removed.' ); - - }, - set: function () { - - console.warn( 'THREE.' + this.type + ': .vertexTangents has been removed.' ); - - } - }, - - } ); - - Object.defineProperties( ShaderMaterial.prototype, { - - derivatives: { - get: function () { - - console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); - return this.extensions.derivatives; - - }, - set: function ( value ) { - - console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); - this.extensions.derivatives = value; - - } - } - - } ); - - // - - WebGLRenderer.prototype.clearTarget = function ( renderTarget, color, depth, stencil ) { - - console.warn( 'THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead.' ); - this.setRenderTarget( renderTarget ); - this.clear( color, depth, stencil ); - - }; - - WebGLRenderer.prototype.animate = function ( callback ) { - - console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' ); - this.setAnimationLoop( callback ); - - }; - - WebGLRenderer.prototype.getCurrentRenderTarget = function () { - - console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' ); - return this.getRenderTarget(); - - }; - - WebGLRenderer.prototype.getMaxAnisotropy = function () { - - console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' ); - return this.capabilities.getMaxAnisotropy(); - - }; - - WebGLRenderer.prototype.getPrecision = function () { - - console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' ); - return this.capabilities.precision; - - }; - - WebGLRenderer.prototype.resetGLState = function () { - - console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' ); - return this.state.reset(); - - }; - - WebGLRenderer.prototype.supportsFloatTextures = function () { - - console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); - return this.extensions.get( 'OES_texture_float' ); - - }; - - WebGLRenderer.prototype.supportsHalfFloatTextures = function () { - - console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); - return this.extensions.get( 'OES_texture_half_float' ); - - }; - - WebGLRenderer.prototype.supportsStandardDerivatives = function () { - - console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); - return this.extensions.get( 'OES_standard_derivatives' ); - - }; - - WebGLRenderer.prototype.supportsCompressedTextureS3TC = function () { - - console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); - return this.extensions.get( 'WEBGL_compressed_texture_s3tc' ); - - }; - - WebGLRenderer.prototype.supportsCompressedTexturePVRTC = function () { - - console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); - return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - - }; - - WebGLRenderer.prototype.supportsBlendMinMax = function () { - - console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); - return this.extensions.get( 'EXT_blend_minmax' ); - - }; - - WebGLRenderer.prototype.supportsVertexTextures = function () { - - console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' ); - return this.capabilities.vertexTextures; - - }; - - WebGLRenderer.prototype.supportsInstancedArrays = function () { - - console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); - return this.extensions.get( 'ANGLE_instanced_arrays' ); - - }; - - WebGLRenderer.prototype.enableScissorTest = function ( boolean ) { - - console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' ); - this.setScissorTest( boolean ); - - }; - - WebGLRenderer.prototype.initMaterial = function () { - - console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); - - }; - - WebGLRenderer.prototype.addPrePlugin = function () { - - console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); - - }; - - WebGLRenderer.prototype.addPostPlugin = function () { - - console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); - - }; - - WebGLRenderer.prototype.updateShadowMap = function () { - - console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); - - }; - - WebGLRenderer.prototype.setFaceCulling = function () { - - console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' ); - - }; - - WebGLRenderer.prototype.allocTextureUnit = function () { - - console.warn( 'THREE.WebGLRenderer: .allocTextureUnit() has been removed.' ); - - }; - - WebGLRenderer.prototype.setTexture = function () { - - console.warn( 'THREE.WebGLRenderer: .setTexture() has been removed.' ); - - }; - - WebGLRenderer.prototype.setTexture2D = function () { - - console.warn( 'THREE.WebGLRenderer: .setTexture2D() has been removed.' ); - - }; - - WebGLRenderer.prototype.setTextureCube = function () { - - console.warn( 'THREE.WebGLRenderer: .setTextureCube() has been removed.' ); - - }; - - WebGLRenderer.prototype.getActiveMipMapLevel = function () { - - console.warn( 'THREE.WebGLRenderer: .getActiveMipMapLevel() is now .getActiveMipmapLevel().' ); - return this.getActiveMipmapLevel(); - - }; - - Object.defineProperties( WebGLRenderer.prototype, { - - shadowMapEnabled: { - get: function () { - - return this.shadowMap.enabled; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); - this.shadowMap.enabled = value; - - } - }, - shadowMapType: { - get: function () { - - return this.shadowMap.type; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); - this.shadowMap.type = value; - - } - }, - shadowMapCullFace: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' ); - return undefined; - - }, - set: function ( /* value */ ) { - - console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' ); - - } - }, - context: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .context has been removed. Use .getContext() instead.' ); - return this.getContext(); - - } - }, - vr: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .vr has been renamed to .xr' ); - return this.xr; - - } - }, - gammaInput: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' ); - return false; - - }, - set: function () { - - console.warn( 'THREE.WebGLRenderer: .gammaInput has been removed. Set the encoding for textures via Texture.encoding instead.' ); - - } - }, - gammaOutput: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' ); - return false; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderer: .gammaOutput has been removed. Set WebGLRenderer.outputEncoding instead.' ); - this.outputEncoding = ( value === true ) ? sRGBEncoding : LinearEncoding; - - } - }, - toneMappingWhitePoint: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' ); - return 1.0; - - }, - set: function () { - - console.warn( 'THREE.WebGLRenderer: .toneMappingWhitePoint has been removed.' ); - - } - }, - - } ); - - Object.defineProperties( WebGLShadowMap.prototype, { - - cullFace: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' ); - return undefined; - - }, - set: function ( /* cullFace */ ) { - - console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' ); - - } - }, - renderReverseSided: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' ); - return undefined; - - }, - set: function () { - - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' ); - - } - }, - renderSingleSided: { - get: function () { - - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' ); - return undefined; - - }, - set: function () { - - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' ); - - } - } - - } ); - - function WebGLRenderTargetCube( width, height, options ) { - - console.warn( 'THREE.WebGLRenderTargetCube( width, height, options ) is now WebGLCubeRenderTarget( size, options ).' ); - return new WebGLCubeRenderTarget( width, options ); - - } - - // - - Object.defineProperties( WebGLRenderTarget.prototype, { - - wrapS: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); - return this.texture.wrapS; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); - this.texture.wrapS = value; - - } - }, - wrapT: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); - return this.texture.wrapT; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); - this.texture.wrapT = value; - - } - }, - magFilter: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); - return this.texture.magFilter; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); - this.texture.magFilter = value; - - } - }, - minFilter: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); - return this.texture.minFilter; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); - this.texture.minFilter = value; - - } - }, - anisotropy: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); - return this.texture.anisotropy; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); - this.texture.anisotropy = value; - - } - }, - offset: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); - return this.texture.offset; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); - this.texture.offset = value; - - } - }, - repeat: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); - return this.texture.repeat; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); - this.texture.repeat = value; - - } - }, - format: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); - return this.texture.format; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); - this.texture.format = value; - - } - }, - type: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); - return this.texture.type; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); - this.texture.type = value; - - } - }, - generateMipmaps: { - get: function () { - - console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); - return this.texture.generateMipmaps; - - }, - set: function ( value ) { - - console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); - this.texture.generateMipmaps = value; - - } - } - - } ); - - // - - Audio.prototype.load = function ( file ) { - - console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' ); - const scope = this; - const audioLoader = new AudioLoader(); - audioLoader.load( file, function ( buffer ) { - - scope.setBuffer( buffer ); - - } ); - return this; - - }; - - - AudioAnalyser.prototype.getData = function () { - - console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' ); - return this.getFrequencyData(); - - }; - - // - - CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) { - - console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' ); - return this.update( renderer, scene ); - - }; - - CubeCamera.prototype.clear = function ( renderer, color, depth, stencil ) { - - console.warn( 'THREE.CubeCamera: .clear() is now .renderTarget.clear().' ); - return this.renderTarget.clear( renderer, color, depth, stencil ); - - }; - - ImageUtils.crossOrigin = undefined; - - ImageUtils.loadTexture = function ( url, mapping, onLoad, onError ) { - - console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' ); - - const loader = new TextureLoader(); - loader.setCrossOrigin( this.crossOrigin ); - - const texture = loader.load( url, onLoad, undefined, onError ); - - if ( mapping ) texture.mapping = mapping; - - return texture; - - }; - - ImageUtils.loadTextureCube = function ( urls, mapping, onLoad, onError ) { - - console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' ); - - const loader = new CubeTextureLoader(); - loader.setCrossOrigin( this.crossOrigin ); - - const texture = loader.load( urls, onLoad, undefined, onError ); - - if ( mapping ) texture.mapping = mapping; - - return texture; - - }; - - ImageUtils.loadCompressedTexture = function () { - - console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ); - - }; - - ImageUtils.loadCompressedTextureCube = function () { - - console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ); - - }; - - // - - function CanvasRenderer() { - - console.error( 'THREE.CanvasRenderer has been removed' ); - - } - - // - - function JSONLoader() { - - console.error( 'THREE.JSONLoader has been removed.' ); - - } - - // - - const SceneUtils = { - - createMultiMaterialObject: function ( /* geometry, materials */ ) { - - console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' ); - - }, - - detach: function ( /* child, parent, scene */ ) { - - console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' ); - - }, - - attach: function ( /* child, scene, parent */ ) { - - console.error( 'THREE.SceneUtils has been moved to /examples/jsm/utils/SceneUtils.js' ); - - } - - }; - - // - - function LensFlare() { - - console.error( 'THREE.LensFlare has been moved to /examples/jsm/objects/Lensflare.js' ); - - } - - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - - /* eslint-disable no-undef */ - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { - revision: REVISION, - } } ) ); - /* eslint-enable no-undef */ - - } - - if ( typeof window !== 'undefined' ) { - - if ( window.__THREE__ ) { - - console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); - - } else { - - window.__THREE__ = REVISION; - - } - - } - - var THREE = /*#__PURE__*/Object.freeze({ - __proto__: null, - ACESFilmicToneMapping: ACESFilmicToneMapping, - AddEquation: AddEquation, - AddOperation: AddOperation, - AdditiveAnimationBlendMode: AdditiveAnimationBlendMode, - AdditiveBlending: AdditiveBlending, - AlphaFormat: AlphaFormat, - AlwaysDepth: AlwaysDepth, - AlwaysStencilFunc: AlwaysStencilFunc, - AmbientLight: AmbientLight, - AmbientLightProbe: AmbientLightProbe, - AnimationClip: AnimationClip, - AnimationLoader: AnimationLoader, - AnimationMixer: AnimationMixer, - AnimationObjectGroup: AnimationObjectGroup, - AnimationUtils: AnimationUtils, - ArcCurve: ArcCurve, - ArrayCamera: ArrayCamera, - ArrowHelper: ArrowHelper, - Audio: Audio, - AudioAnalyser: AudioAnalyser, - AudioContext: AudioContext, - AudioListener: AudioListener, - AudioLoader: AudioLoader, - AxesHelper: AxesHelper, - AxisHelper: AxisHelper, - BackSide: BackSide, - BasicDepthPacking: BasicDepthPacking, - BasicShadowMap: BasicShadowMap, - BinaryTextureLoader: BinaryTextureLoader, - Bone: Bone, - BooleanKeyframeTrack: BooleanKeyframeTrack, - BoundingBoxHelper: BoundingBoxHelper, - Box2: Box2, - Box3: Box3, - Box3Helper: Box3Helper, - BoxBufferGeometry: BoxGeometry, - BoxGeometry: BoxGeometry, - BoxHelper: BoxHelper, - BufferAttribute: BufferAttribute, - BufferGeometry: BufferGeometry, - BufferGeometryLoader: BufferGeometryLoader, - ByteType: ByteType, - Cache: Cache, - Camera: Camera, - CameraHelper: CameraHelper, - CanvasRenderer: CanvasRenderer, - CanvasTexture: CanvasTexture, - CatmullRomCurve3: CatmullRomCurve3, - CineonToneMapping: CineonToneMapping, - CircleBufferGeometry: CircleGeometry, - CircleGeometry: CircleGeometry, - ClampToEdgeWrapping: ClampToEdgeWrapping, - Clock: Clock, - Color: Color, - ColorKeyframeTrack: ColorKeyframeTrack, - CompressedTexture: CompressedTexture, - CompressedTextureLoader: CompressedTextureLoader, - ConeBufferGeometry: ConeGeometry, - ConeGeometry: ConeGeometry, - CubeCamera: CubeCamera, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - CubeTexture: CubeTexture, - CubeTextureLoader: CubeTextureLoader, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubeUVRefractionMapping: CubeUVRefractionMapping, - CubicBezierCurve: CubicBezierCurve, - CubicBezierCurve3: CubicBezierCurve3, - CubicInterpolant: CubicInterpolant, - CullFaceBack: CullFaceBack, - CullFaceFront: CullFaceFront, - CullFaceFrontBack: CullFaceFrontBack, - CullFaceNone: CullFaceNone, - Curve: Curve, - CurvePath: CurvePath, - CustomBlending: CustomBlending, - CustomToneMapping: CustomToneMapping, - CylinderBufferGeometry: CylinderGeometry, - CylinderGeometry: CylinderGeometry, - Cylindrical: Cylindrical, - DataTexture: DataTexture, - DataTexture2DArray: DataTexture2DArray, - DataTexture3D: DataTexture3D, - DataTextureLoader: DataTextureLoader, - DataUtils: DataUtils, - DecrementStencilOp: DecrementStencilOp, - DecrementWrapStencilOp: DecrementWrapStencilOp, - DefaultLoadingManager: DefaultLoadingManager, - DepthFormat: DepthFormat, - DepthStencilFormat: DepthStencilFormat, - DepthTexture: DepthTexture, - DirectionalLight: DirectionalLight, - DirectionalLightHelper: DirectionalLightHelper, - DiscreteInterpolant: DiscreteInterpolant, - DodecahedronBufferGeometry: DodecahedronGeometry, - DodecahedronGeometry: DodecahedronGeometry, - DoubleSide: DoubleSide, - DstAlphaFactor: DstAlphaFactor, - DstColorFactor: DstColorFactor, - DynamicBufferAttribute: DynamicBufferAttribute, - DynamicCopyUsage: DynamicCopyUsage, - DynamicDrawUsage: DynamicDrawUsage, - DynamicReadUsage: DynamicReadUsage, - EdgesGeometry: EdgesGeometry, - EdgesHelper: EdgesHelper, - EllipseCurve: EllipseCurve, - EqualDepth: EqualDepth, - EqualStencilFunc: EqualStencilFunc, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - Euler: Euler, - EventDispatcher: EventDispatcher, - ExtrudeBufferGeometry: ExtrudeGeometry, - ExtrudeGeometry: ExtrudeGeometry, - FaceColors: FaceColors, - FileLoader: FileLoader, - FlatShading: FlatShading, - Float16BufferAttribute: Float16BufferAttribute, - Float32Attribute: Float32Attribute, - Float32BufferAttribute: Float32BufferAttribute, - Float64Attribute: Float64Attribute, - Float64BufferAttribute: Float64BufferAttribute, - FloatType: FloatType, - Fog: Fog, - FogExp2: FogExp2, - Font: Font, - FontLoader: FontLoader, - FrontSide: FrontSide, - Frustum: Frustum, - GLBufferAttribute: GLBufferAttribute, - GLSL1: GLSL1, - GLSL3: GLSL3, - GammaEncoding: GammaEncoding, - GreaterDepth: GreaterDepth, - GreaterEqualDepth: GreaterEqualDepth, - GreaterEqualStencilFunc: GreaterEqualStencilFunc, - GreaterStencilFunc: GreaterStencilFunc, - GridHelper: GridHelper, - Group: Group, - HalfFloatType: HalfFloatType, - HemisphereLight: HemisphereLight, - HemisphereLightHelper: HemisphereLightHelper, - HemisphereLightProbe: HemisphereLightProbe, - IcosahedronBufferGeometry: IcosahedronGeometry, - IcosahedronGeometry: IcosahedronGeometry, - ImageBitmapLoader: ImageBitmapLoader, - ImageLoader: ImageLoader, - ImageUtils: ImageUtils, - ImmediateRenderObject: ImmediateRenderObject, - IncrementStencilOp: IncrementStencilOp, - IncrementWrapStencilOp: IncrementWrapStencilOp, - InstancedBufferAttribute: InstancedBufferAttribute, - InstancedBufferGeometry: InstancedBufferGeometry, - InstancedInterleavedBuffer: InstancedInterleavedBuffer, - InstancedMesh: InstancedMesh, - Int16Attribute: Int16Attribute, - Int16BufferAttribute: Int16BufferAttribute, - Int32Attribute: Int32Attribute, - Int32BufferAttribute: Int32BufferAttribute, - Int8Attribute: Int8Attribute, - Int8BufferAttribute: Int8BufferAttribute, - IntType: IntType, - InterleavedBuffer: InterleavedBuffer, - InterleavedBufferAttribute: InterleavedBufferAttribute, - Interpolant: Interpolant, - InterpolateDiscrete: InterpolateDiscrete, - InterpolateLinear: InterpolateLinear, - InterpolateSmooth: InterpolateSmooth, - InvertStencilOp: InvertStencilOp, - JSONLoader: JSONLoader, - KeepStencilOp: KeepStencilOp, - KeyframeTrack: KeyframeTrack, - LOD: LOD, - LatheBufferGeometry: LatheGeometry, - LatheGeometry: LatheGeometry, - Layers: Layers, - LensFlare: LensFlare, - LessDepth: LessDepth, - LessEqualDepth: LessEqualDepth, - LessEqualStencilFunc: LessEqualStencilFunc, - LessStencilFunc: LessStencilFunc, - Light: Light, - LightProbe: LightProbe, - Line: Line, - Line3: Line3, - LineBasicMaterial: LineBasicMaterial, - LineCurve: LineCurve, - LineCurve3: LineCurve3, - LineDashedMaterial: LineDashedMaterial, - LineLoop: LineLoop, - LinePieces: LinePieces, - LineSegments: LineSegments, - LineStrip: LineStrip, - LinearEncoding: LinearEncoding, - LinearFilter: LinearFilter, - LinearInterpolant: LinearInterpolant, - LinearMipMapLinearFilter: LinearMipMapLinearFilter, - LinearMipMapNearestFilter: LinearMipMapNearestFilter, - LinearMipmapLinearFilter: LinearMipmapLinearFilter, - LinearMipmapNearestFilter: LinearMipmapNearestFilter, - LinearToneMapping: LinearToneMapping, - Loader: Loader, - LoaderUtils: LoaderUtils, - LoadingManager: LoadingManager, - LogLuvEncoding: LogLuvEncoding, - LoopOnce: LoopOnce, - LoopPingPong: LoopPingPong, - LoopRepeat: LoopRepeat, - LuminanceAlphaFormat: LuminanceAlphaFormat, - LuminanceFormat: LuminanceFormat, - MOUSE: MOUSE, - Material: Material, - MaterialLoader: MaterialLoader, - Math: MathUtils, - MathUtils: MathUtils, - Matrix3: Matrix3, - Matrix4: Matrix4, - MaxEquation: MaxEquation, - Mesh: Mesh, - MeshBasicMaterial: MeshBasicMaterial, - MeshDepthMaterial: MeshDepthMaterial, - MeshDistanceMaterial: MeshDistanceMaterial, - MeshFaceMaterial: MeshFaceMaterial, - MeshLambertMaterial: MeshLambertMaterial, - MeshMatcapMaterial: MeshMatcapMaterial, - MeshNormalMaterial: MeshNormalMaterial, - MeshPhongMaterial: MeshPhongMaterial, - MeshPhysicalMaterial: MeshPhysicalMaterial, - MeshStandardMaterial: MeshStandardMaterial, - MeshToonMaterial: MeshToonMaterial, - MinEquation: MinEquation, - MirroredRepeatWrapping: MirroredRepeatWrapping, - MixOperation: MixOperation, - MultiMaterial: MultiMaterial, - MultiplyBlending: MultiplyBlending, - MultiplyOperation: MultiplyOperation, - NearestFilter: NearestFilter, - NearestMipMapLinearFilter: NearestMipMapLinearFilter, - NearestMipMapNearestFilter: NearestMipMapNearestFilter, - NearestMipmapLinearFilter: NearestMipmapLinearFilter, - NearestMipmapNearestFilter: NearestMipmapNearestFilter, - NeverDepth: NeverDepth, - NeverStencilFunc: NeverStencilFunc, - NoBlending: NoBlending, - NoColors: NoColors, - NoToneMapping: NoToneMapping, - NormalAnimationBlendMode: NormalAnimationBlendMode, - NormalBlending: NormalBlending, - NotEqualDepth: NotEqualDepth, - NotEqualStencilFunc: NotEqualStencilFunc, - NumberKeyframeTrack: NumberKeyframeTrack, - Object3D: Object3D, - ObjectLoader: ObjectLoader, - ObjectSpaceNormalMap: ObjectSpaceNormalMap, - OctahedronBufferGeometry: OctahedronGeometry, - OctahedronGeometry: OctahedronGeometry, - OneFactor: OneFactor, - OneMinusDstAlphaFactor: OneMinusDstAlphaFactor, - OneMinusDstColorFactor: OneMinusDstColorFactor, - OneMinusSrcAlphaFactor: OneMinusSrcAlphaFactor, - OneMinusSrcColorFactor: OneMinusSrcColorFactor, - OrthographicCamera: OrthographicCamera, - PCFShadowMap: PCFShadowMap, - PCFSoftShadowMap: PCFSoftShadowMap, - PMREMGenerator: PMREMGenerator, - ParametricBufferGeometry: ParametricGeometry, - ParametricGeometry: ParametricGeometry, - Particle: Particle, - ParticleBasicMaterial: ParticleBasicMaterial, - ParticleSystem: ParticleSystem, - ParticleSystemMaterial: ParticleSystemMaterial, - Path: Path, - PerspectiveCamera: PerspectiveCamera, - Plane: Plane, - PlaneBufferGeometry: PlaneGeometry, - PlaneGeometry: PlaneGeometry, - PlaneHelper: PlaneHelper, - PointCloud: PointCloud, - PointCloudMaterial: PointCloudMaterial, - PointLight: PointLight, - PointLightHelper: PointLightHelper, - Points: Points, - PointsMaterial: PointsMaterial, - PolarGridHelper: PolarGridHelper, - PolyhedronBufferGeometry: PolyhedronGeometry, - PolyhedronGeometry: PolyhedronGeometry, - PositionalAudio: PositionalAudio, - PropertyBinding: PropertyBinding, - PropertyMixer: PropertyMixer, - QuadraticBezierCurve: QuadraticBezierCurve, - QuadraticBezierCurve3: QuadraticBezierCurve3, - Quaternion: Quaternion, - QuaternionKeyframeTrack: QuaternionKeyframeTrack, - QuaternionLinearInterpolant: QuaternionLinearInterpolant, - REVISION: REVISION, - RGBADepthPacking: RGBADepthPacking, - RGBAFormat: RGBAFormat, - RGBAIntegerFormat: RGBAIntegerFormat, - RGBA_ASTC_10x10_Format: RGBA_ASTC_10x10_Format, - RGBA_ASTC_10x5_Format: RGBA_ASTC_10x5_Format, - RGBA_ASTC_10x6_Format: RGBA_ASTC_10x6_Format, - RGBA_ASTC_10x8_Format: RGBA_ASTC_10x8_Format, - RGBA_ASTC_12x10_Format: RGBA_ASTC_12x10_Format, - RGBA_ASTC_12x12_Format: RGBA_ASTC_12x12_Format, - RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, - RGBA_ASTC_5x4_Format: RGBA_ASTC_5x4_Format, - RGBA_ASTC_5x5_Format: RGBA_ASTC_5x5_Format, - RGBA_ASTC_6x5_Format: RGBA_ASTC_6x5_Format, - RGBA_ASTC_6x6_Format: RGBA_ASTC_6x6_Format, - RGBA_ASTC_8x5_Format: RGBA_ASTC_8x5_Format, - RGBA_ASTC_8x6_Format: RGBA_ASTC_8x6_Format, - RGBA_ASTC_8x8_Format: RGBA_ASTC_8x8_Format, - RGBA_BPTC_Format: RGBA_BPTC_Format, - RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, - RGBA_PVRTC_2BPPV1_Format: RGBA_PVRTC_2BPPV1_Format, - RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, - RGBA_S3TC_DXT1_Format: RGBA_S3TC_DXT1_Format, - RGBA_S3TC_DXT3_Format: RGBA_S3TC_DXT3_Format, - RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, - RGBDEncoding: RGBDEncoding, - RGBEEncoding: RGBEEncoding, - RGBEFormat: RGBEFormat, - RGBFormat: RGBFormat, - RGBIntegerFormat: RGBIntegerFormat, - RGBM16Encoding: RGBM16Encoding, - RGBM7Encoding: RGBM7Encoding, - RGB_ETC1_Format: RGB_ETC1_Format, - RGB_ETC2_Format: RGB_ETC2_Format, - RGB_PVRTC_2BPPV1_Format: RGB_PVRTC_2BPPV1_Format, - RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, - RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format, - RGFormat: RGFormat, - RGIntegerFormat: RGIntegerFormat, - RawShaderMaterial: RawShaderMaterial, - Ray: Ray, - Raycaster: Raycaster, - RectAreaLight: RectAreaLight, - RedFormat: RedFormat, - RedIntegerFormat: RedIntegerFormat, - ReinhardToneMapping: ReinhardToneMapping, - RepeatWrapping: RepeatWrapping, - ReplaceStencilOp: ReplaceStencilOp, - ReverseSubtractEquation: ReverseSubtractEquation, - RingBufferGeometry: RingGeometry, - RingGeometry: RingGeometry, - SRGB8_ALPHA8_ASTC_10x10_Format: SRGB8_ALPHA8_ASTC_10x10_Format, - SRGB8_ALPHA8_ASTC_10x5_Format: SRGB8_ALPHA8_ASTC_10x5_Format, - SRGB8_ALPHA8_ASTC_10x6_Format: SRGB8_ALPHA8_ASTC_10x6_Format, - SRGB8_ALPHA8_ASTC_10x8_Format: SRGB8_ALPHA8_ASTC_10x8_Format, - SRGB8_ALPHA8_ASTC_12x10_Format: SRGB8_ALPHA8_ASTC_12x10_Format, - SRGB8_ALPHA8_ASTC_12x12_Format: SRGB8_ALPHA8_ASTC_12x12_Format, - SRGB8_ALPHA8_ASTC_4x4_Format: SRGB8_ALPHA8_ASTC_4x4_Format, - SRGB8_ALPHA8_ASTC_5x4_Format: SRGB8_ALPHA8_ASTC_5x4_Format, - SRGB8_ALPHA8_ASTC_5x5_Format: SRGB8_ALPHA8_ASTC_5x5_Format, - SRGB8_ALPHA8_ASTC_6x5_Format: SRGB8_ALPHA8_ASTC_6x5_Format, - SRGB8_ALPHA8_ASTC_6x6_Format: SRGB8_ALPHA8_ASTC_6x6_Format, - SRGB8_ALPHA8_ASTC_8x5_Format: SRGB8_ALPHA8_ASTC_8x5_Format, - SRGB8_ALPHA8_ASTC_8x6_Format: SRGB8_ALPHA8_ASTC_8x6_Format, - SRGB8_ALPHA8_ASTC_8x8_Format: SRGB8_ALPHA8_ASTC_8x8_Format, - Scene: Scene, - SceneUtils: SceneUtils, - ShaderChunk: ShaderChunk, - ShaderLib: ShaderLib, - ShaderMaterial: ShaderMaterial, - ShadowMaterial: ShadowMaterial, - Shape: Shape, - ShapeBufferGeometry: ShapeGeometry, - ShapeGeometry: ShapeGeometry, - ShapePath: ShapePath, - ShapeUtils: ShapeUtils, - ShortType: ShortType, - Skeleton: Skeleton, - SkeletonHelper: SkeletonHelper, - SkinnedMesh: SkinnedMesh, - SmoothShading: SmoothShading, - Sphere: Sphere, - SphereBufferGeometry: SphereGeometry, - SphereGeometry: SphereGeometry, - Spherical: Spherical, - SphericalHarmonics3: SphericalHarmonics3, - SplineCurve: SplineCurve, - SpotLight: SpotLight, - SpotLightHelper: SpotLightHelper, - Sprite: Sprite, - SpriteMaterial: SpriteMaterial, - SrcAlphaFactor: SrcAlphaFactor, - SrcAlphaSaturateFactor: SrcAlphaSaturateFactor, - SrcColorFactor: SrcColorFactor, - StaticCopyUsage: StaticCopyUsage, - StaticDrawUsage: StaticDrawUsage, - StaticReadUsage: StaticReadUsage, - StereoCamera: StereoCamera, - StreamCopyUsage: StreamCopyUsage, - StreamDrawUsage: StreamDrawUsage, - StreamReadUsage: StreamReadUsage, - StringKeyframeTrack: StringKeyframeTrack, - SubtractEquation: SubtractEquation, - SubtractiveBlending: SubtractiveBlending, - TOUCH: TOUCH, - TangentSpaceNormalMap: TangentSpaceNormalMap, - TetrahedronBufferGeometry: TetrahedronGeometry, - TetrahedronGeometry: TetrahedronGeometry, - TextBufferGeometry: TextGeometry, - TextGeometry: TextGeometry, - Texture: Texture, - TextureLoader: TextureLoader, - TorusBufferGeometry: TorusGeometry, - TorusGeometry: TorusGeometry, - TorusKnotBufferGeometry: TorusKnotGeometry, - TorusKnotGeometry: TorusKnotGeometry, - Triangle: Triangle, - TriangleFanDrawMode: TriangleFanDrawMode, - TriangleStripDrawMode: TriangleStripDrawMode, - TrianglesDrawMode: TrianglesDrawMode, - TubeBufferGeometry: TubeGeometry, - TubeGeometry: TubeGeometry, - UVMapping: UVMapping, - Uint16Attribute: Uint16Attribute, - Uint16BufferAttribute: Uint16BufferAttribute, - Uint32Attribute: Uint32Attribute, - Uint32BufferAttribute: Uint32BufferAttribute, - Uint8Attribute: Uint8Attribute, - Uint8BufferAttribute: Uint8BufferAttribute, - Uint8ClampedAttribute: Uint8ClampedAttribute, - Uint8ClampedBufferAttribute: Uint8ClampedBufferAttribute, - Uniform: Uniform, - UniformsLib: UniformsLib, - UniformsUtils: UniformsUtils, - UnsignedByteType: UnsignedByteType, - UnsignedInt248Type: UnsignedInt248Type, - UnsignedIntType: UnsignedIntType, - UnsignedShort4444Type: UnsignedShort4444Type, - UnsignedShort5551Type: UnsignedShort5551Type, - UnsignedShort565Type: UnsignedShort565Type, - UnsignedShortType: UnsignedShortType, - VSMShadowMap: VSMShadowMap, - Vector2: Vector2, - Vector3: Vector3, - Vector4: Vector4, - VectorKeyframeTrack: VectorKeyframeTrack, - Vertex: Vertex, - VertexColors: VertexColors, - VideoTexture: VideoTexture, - WebGL1Renderer: WebGL1Renderer, - WebGLCubeRenderTarget: WebGLCubeRenderTarget, - WebGLMultipleRenderTargets: WebGLMultipleRenderTargets, - WebGLMultisampleRenderTarget: WebGLMultisampleRenderTarget, - WebGLRenderTarget: WebGLRenderTarget, - WebGLRenderTargetCube: WebGLRenderTargetCube, - WebGLRenderer: WebGLRenderer, - WebGLUtils: WebGLUtils, - WireframeGeometry: WireframeGeometry, - WireframeHelper: WireframeHelper, - WrapAroundEnding: WrapAroundEnding, - XHRLoader: XHRLoader, - ZeroCurvatureEnding: ZeroCurvatureEnding, - ZeroFactor: ZeroFactor, - ZeroSlopeEnding: ZeroSlopeEnding, - ZeroStencilOp: ZeroStencilOp, - sRGBEncoding: sRGBEncoding - }); - - const _changeEvent = { type: 'change' }; - const _startEvent = { type: 'start' }; - const _endEvent = { type: 'end' }; - - class TrackballControls extends EventDispatcher { - - constructor( object, domElement ) { - - super(); - - if ( domElement === undefined ) console.warn( 'THREE.TrackballControls: The second parameter "domElement" is now mandatory.' ); - if ( domElement === document ) console.error( 'THREE.TrackballControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' ); - - const scope = this; - const STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; - - this.object = object; - this.domElement = domElement; - this.domElement.style.touchAction = 'none'; // disable touch scroll - - // API - - this.enabled = true; - - this.screen = { left: 0, top: 0, width: 0, height: 0 }; - - this.rotateSpeed = 1.0; - this.zoomSpeed = 1.2; - this.panSpeed = 0.3; - - this.noRotate = false; - this.noZoom = false; - this.noPan = false; - - this.staticMoving = false; - this.dynamicDampingFactor = 0.2; - - this.minDistance = 0; - this.maxDistance = Infinity; - - this.keys = [ 'KeyA' /*A*/, 'KeyS' /*S*/, 'KeyD' /*D*/ ]; - - this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }; - - // internals - - this.target = new Vector3(); - - const EPS = 0.000001; - - const lastPosition = new Vector3(); - let lastZoom = 1; - - let _state = STATE.NONE, - _keyState = STATE.NONE, - - _touchZoomDistanceStart = 0, - _touchZoomDistanceEnd = 0, - - _lastAngle = 0; - - const _eye = new Vector3(), - - _movePrev = new Vector2(), - _moveCurr = new Vector2(), - - _lastAxis = new Vector3(), - - _zoomStart = new Vector2(), - _zoomEnd = new Vector2(), - - _panStart = new Vector2(), - _panEnd = new Vector2(), - - _pointers = [], - _pointerPositions = {}; - - // for reset - - this.target0 = this.target.clone(); - this.position0 = this.object.position.clone(); - this.up0 = this.object.up.clone(); - this.zoom0 = this.object.zoom; - - // methods - - this.handleResize = function () { - - const box = scope.domElement.getBoundingClientRect(); - // adjustments come from similar code in the jquery offset() function - const d = scope.domElement.ownerDocument.documentElement; - scope.screen.left = box.left + window.pageXOffset - d.clientLeft; - scope.screen.top = box.top + window.pageYOffset - d.clientTop; - scope.screen.width = box.width; - scope.screen.height = box.height; - - }; - - const getMouseOnScreen = ( function () { - - const vector = new Vector2(); - - return function getMouseOnScreen( pageX, pageY ) { - - vector.set( - ( pageX - scope.screen.left ) / scope.screen.width, - ( pageY - scope.screen.top ) / scope.screen.height - ); - - return vector; - - }; - - }() ); - - const getMouseOnCircle = ( function () { - - const vector = new Vector2(); - - return function getMouseOnCircle( pageX, pageY ) { - - vector.set( - ( ( pageX - scope.screen.width * 0.5 - scope.screen.left ) / ( scope.screen.width * 0.5 ) ), - ( ( scope.screen.height + 2 * ( scope.screen.top - pageY ) ) / scope.screen.width ) // screen.width intentional - ); - - return vector; - - }; - - }() ); - - this.rotateCamera = ( function () { - - const axis = new Vector3(), - quaternion = new Quaternion(), - eyeDirection = new Vector3(), - objectUpDirection = new Vector3(), - objectSidewaysDirection = new Vector3(), - moveDirection = new Vector3(); - - return function rotateCamera() { - - moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 ); - let angle = moveDirection.length(); - - if ( angle ) { - - _eye.copy( scope.object.position ).sub( scope.target ); - - eyeDirection.copy( _eye ).normalize(); - objectUpDirection.copy( scope.object.up ).normalize(); - objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize(); - - objectUpDirection.setLength( _moveCurr.y - _movePrev.y ); - objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x ); - - moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) ); - - axis.crossVectors( moveDirection, _eye ).normalize(); - - angle *= scope.rotateSpeed; - quaternion.setFromAxisAngle( axis, angle ); - - _eye.applyQuaternion( quaternion ); - scope.object.up.applyQuaternion( quaternion ); - - _lastAxis.copy( axis ); - _lastAngle = angle; - - } else if ( ! scope.staticMoving && _lastAngle ) { - - _lastAngle *= Math.sqrt( 1.0 - scope.dynamicDampingFactor ); - _eye.copy( scope.object.position ).sub( scope.target ); - quaternion.setFromAxisAngle( _lastAxis, _lastAngle ); - _eye.applyQuaternion( quaternion ); - scope.object.up.applyQuaternion( quaternion ); - - } - - _movePrev.copy( _moveCurr ); - - }; - - }() ); - - - this.zoomCamera = function () { - - let factor; - - if ( _state === STATE.TOUCH_ZOOM_PAN ) { - - factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; - _touchZoomDistanceStart = _touchZoomDistanceEnd; - - if ( scope.object.isPerspectiveCamera ) { - - _eye.multiplyScalar( factor ); - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom *= factor; - scope.object.updateProjectionMatrix(); - - } else { - - console.warn( 'THREE.TrackballControls: Unsupported camera type' ); - - } - - } else { - - factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * scope.zoomSpeed; - - if ( factor !== 1.0 && factor > 0.0 ) { - - if ( scope.object.isPerspectiveCamera ) { - - _eye.multiplyScalar( factor ); - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom /= factor; - scope.object.updateProjectionMatrix(); - - } else { - - console.warn( 'THREE.TrackballControls: Unsupported camera type' ); - - } - - } - - if ( scope.staticMoving ) { - - _zoomStart.copy( _zoomEnd ); - - } else { - - _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; - - } - - } - - }; - - this.panCamera = ( function () { - - const mouseChange = new Vector2(), - objectUp = new Vector3(), - pan = new Vector3(); - - return function panCamera() { - - mouseChange.copy( _panEnd ).sub( _panStart ); - - if ( mouseChange.lengthSq() ) { - - if ( scope.object.isOrthographicCamera ) { - - const scale_x = ( scope.object.right - scope.object.left ) / scope.object.zoom / scope.domElement.clientWidth; - const scale_y = ( scope.object.top - scope.object.bottom ) / scope.object.zoom / scope.domElement.clientWidth; - - mouseChange.x *= scale_x; - mouseChange.y *= scale_y; - - } - - mouseChange.multiplyScalar( _eye.length() * scope.panSpeed ); - - pan.copy( _eye ).cross( scope.object.up ).setLength( mouseChange.x ); - pan.add( objectUp.copy( scope.object.up ).setLength( mouseChange.y ) ); - - scope.object.position.add( pan ); - scope.target.add( pan ); - - if ( scope.staticMoving ) { - - _panStart.copy( _panEnd ); - - } else { - - _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( scope.dynamicDampingFactor ) ); - - } - - } - - }; - - }() ); - - this.checkDistances = function () { - - if ( ! scope.noZoom || ! scope.noPan ) { - - if ( _eye.lengthSq() > scope.maxDistance * scope.maxDistance ) { - - scope.object.position.addVectors( scope.target, _eye.setLength( scope.maxDistance ) ); - _zoomStart.copy( _zoomEnd ); - - } - - if ( _eye.lengthSq() < scope.minDistance * scope.minDistance ) { - - scope.object.position.addVectors( scope.target, _eye.setLength( scope.minDistance ) ); - _zoomStart.copy( _zoomEnd ); - - } - - } - - }; - - this.update = function () { - - _eye.subVectors( scope.object.position, scope.target ); - - if ( ! scope.noRotate ) { - - scope.rotateCamera(); - - } - - if ( ! scope.noZoom ) { - - scope.zoomCamera(); - - } - - if ( ! scope.noPan ) { - - scope.panCamera(); - - } - - scope.object.position.addVectors( scope.target, _eye ); - - if ( scope.object.isPerspectiveCamera ) { - - scope.checkDistances(); - - scope.object.lookAt( scope.target ); - - if ( lastPosition.distanceToSquared( scope.object.position ) > EPS ) { - - scope.dispatchEvent( _changeEvent ); - - lastPosition.copy( scope.object.position ); - - } - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.lookAt( scope.target ); - - if ( lastPosition.distanceToSquared( scope.object.position ) > EPS || lastZoom !== scope.object.zoom ) { - - scope.dispatchEvent( _changeEvent ); - - lastPosition.copy( scope.object.position ); - lastZoom = scope.object.zoom; - - } - - } else { - - console.warn( 'THREE.TrackballControls: Unsupported camera type' ); - - } - - }; - - this.reset = function () { - - _state = STATE.NONE; - _keyState = STATE.NONE; - - scope.target.copy( scope.target0 ); - scope.object.position.copy( scope.position0 ); - scope.object.up.copy( scope.up0 ); - scope.object.zoom = scope.zoom0; - - scope.object.updateProjectionMatrix(); - - _eye.subVectors( scope.object.position, scope.target ); - - scope.object.lookAt( scope.target ); - - scope.dispatchEvent( _changeEvent ); - - lastPosition.copy( scope.object.position ); - lastZoom = scope.object.zoom; - - }; - - // listeners - - function onPointerDown( event ) { - - if ( scope.enabled === false ) return; - - if ( _pointers.length === 0 ) { - - scope.domElement.setPointerCapture( event.pointerId ); - - scope.domElement.addEventListener( 'pointermove', onPointerMove ); - scope.domElement.addEventListener( 'pointerup', onPointerUp ); - - } - - // - - addPointer( event ); - - if ( event.pointerType === 'touch' ) { - - onTouchStart( event ); - - } else { - - onMouseDown( event ); - - } - - } - - function onPointerMove( event ) { - - if ( scope.enabled === false ) return; - - if ( event.pointerType === 'touch' ) { - - onTouchMove( event ); - - } else { - - onMouseMove( event ); - - } - - } - - function onPointerUp( event ) { - - if ( scope.enabled === false ) return; - - if ( event.pointerType === 'touch' ) { - - onTouchEnd( event ); - - } else { - - onMouseUp(); - - } - - // - - removePointer( event ); - - if ( _pointers.length === 0 ) { - - scope.domElement.releasePointerCapture( event.pointerId ); - - scope.domElement.removeEventListener( 'pointermove', onPointerMove ); - scope.domElement.removeEventListener( 'pointerup', onPointerUp ); - - } - - - } - - function onPointerCancel( event ) { - - removePointer( event ); - - } - - function keydown( event ) { - - if ( scope.enabled === false ) return; - - window.removeEventListener( 'keydown', keydown ); - - if ( _keyState !== STATE.NONE ) { - - return; - - } else if ( event.code === scope.keys[ STATE.ROTATE ] && ! scope.noRotate ) { - - _keyState = STATE.ROTATE; - - } else if ( event.code === scope.keys[ STATE.ZOOM ] && ! scope.noZoom ) { - - _keyState = STATE.ZOOM; - - } else if ( event.code === scope.keys[ STATE.PAN ] && ! scope.noPan ) { - - _keyState = STATE.PAN; - - } - - } - - function keyup() { - - if ( scope.enabled === false ) return; - - _keyState = STATE.NONE; - - window.addEventListener( 'keydown', keydown ); - - } - - function onMouseDown( event ) { - - if ( _state === STATE.NONE ) { - - switch ( event.button ) { - - case scope.mouseButtons.LEFT: - _state = STATE.ROTATE; - break; - - case scope.mouseButtons.MIDDLE: - _state = STATE.ZOOM; - break; - - case scope.mouseButtons.RIGHT: - _state = STATE.PAN; - break; - - default: - _state = STATE.NONE; - - } - - } - - const state = ( _keyState !== STATE.NONE ) ? _keyState : _state; - - if ( state === STATE.ROTATE && ! scope.noRotate ) { - - _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); - _movePrev.copy( _moveCurr ); - - } else if ( state === STATE.ZOOM && ! scope.noZoom ) { - - _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - _zoomEnd.copy( _zoomStart ); - - } else if ( state === STATE.PAN && ! scope.noPan ) { - - _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - _panEnd.copy( _panStart ); - - } - - scope.dispatchEvent( _startEvent ); - - } - - function onMouseMove( event ) { - - const state = ( _keyState !== STATE.NONE ) ? _keyState : _state; - - if ( state === STATE.ROTATE && ! scope.noRotate ) { - - _movePrev.copy( _moveCurr ); - _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); - - } else if ( state === STATE.ZOOM && ! scope.noZoom ) { - - _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - - } else if ( state === STATE.PAN && ! scope.noPan ) { - - _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - - } - - } - - function onMouseUp() { - - _state = STATE.NONE; - - scope.dispatchEvent( _endEvent ); - - } - - function onMouseWheel( event ) { - - if ( scope.enabled === false ) return; - - if ( scope.noZoom === true ) return; - - event.preventDefault(); - - switch ( event.deltaMode ) { - - case 2: - // Zoom in pages - _zoomStart.y -= event.deltaY * 0.025; - break; - - case 1: - // Zoom in lines - _zoomStart.y -= event.deltaY * 0.01; - break; - - default: - // undefined, 0, assume pixels - _zoomStart.y -= event.deltaY * 0.00025; - break; - - } - - scope.dispatchEvent( _startEvent ); - scope.dispatchEvent( _endEvent ); - - } - - function onTouchStart( event ) { - - trackPointer( event ); - - switch ( _pointers.length ) { - - case 1: - _state = STATE.TOUCH_ROTATE; - _moveCurr.copy( getMouseOnCircle( _pointers[ 0 ].pageX, _pointers[ 0 ].pageY ) ); - _movePrev.copy( _moveCurr ); - break; - - default: // 2 or more - _state = STATE.TOUCH_ZOOM_PAN; - const dx = _pointers[ 0 ].pageX - _pointers[ 1 ].pageX; - const dy = _pointers[ 0 ].pageY - _pointers[ 1 ].pageY; - _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); - - const x = ( _pointers[ 0 ].pageX + _pointers[ 1 ].pageX ) / 2; - const y = ( _pointers[ 0 ].pageY + _pointers[ 1 ].pageY ) / 2; - _panStart.copy( getMouseOnScreen( x, y ) ); - _panEnd.copy( _panStart ); - break; - - } - - scope.dispatchEvent( _startEvent ); - - } - - function onTouchMove( event ) { - - trackPointer( event ); - - switch ( _pointers.length ) { - - case 1: - _movePrev.copy( _moveCurr ); - _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); - break; - - default: // 2 or more - - const position = getSecondPointerPosition( event ); - - const dx = event.pageX - position.x; - const dy = event.pageY - position.y; - _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); - - const x = ( event.pageX + position.x ) / 2; - const y = ( event.pageY + position.y ) / 2; - _panEnd.copy( getMouseOnScreen( x, y ) ); - break; - - } - - } - - function onTouchEnd( event ) { - - switch ( _pointers.length ) { - - case 0: - _state = STATE.NONE; - break; - - case 1: - _state = STATE.TOUCH_ROTATE; - _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); - _movePrev.copy( _moveCurr ); - break; - - case 2: - _state = STATE.TOUCH_ZOOM_PAN; - _moveCurr.copy( getMouseOnCircle( event.pageX - _movePrev.pageX, event.pageY - _movePrev.pageY ) ); - _movePrev.copy( _moveCurr ); - break; - - } - - scope.dispatchEvent( _endEvent ); - - } - - function contextmenu( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - } - - function addPointer( event ) { - - _pointers.push( event ); - - } - - function removePointer( event ) { - - delete _pointerPositions[ event.pointerId ]; - - for ( let i = 0; i < _pointers.length; i ++ ) { - - if ( _pointers[ i ].pointerId == event.pointerId ) { - - _pointers.splice( i, 1 ); - return; - - } - - } - - } - - function trackPointer( event ) { - - let position = _pointerPositions[ event.pointerId ]; - - if ( position === undefined ) { - - position = new Vector2(); - _pointerPositions[ event.pointerId ] = position; - - } - - position.set( event.pageX, event.pageY ); - - } - - function getSecondPointerPosition( event ) { - - const pointer = ( event.pointerId === _pointers[ 0 ].pointerId ) ? _pointers[ 1 ] : _pointers[ 0 ]; - - return _pointerPositions[ pointer.pointerId ]; - - } - - this.dispose = function () { - - scope.domElement.removeEventListener( 'contextmenu', contextmenu ); - - scope.domElement.removeEventListener( 'pointerdown', onPointerDown ); - scope.domElement.removeEventListener( 'pointercancel', onPointerCancel ); - scope.domElement.removeEventListener( 'wheel', onMouseWheel ); - - scope.domElement.removeEventListener( 'pointermove', onPointerMove ); - scope.domElement.removeEventListener( 'pointerup', onPointerUp ); - - window.removeEventListener( 'keydown', keydown ); - window.removeEventListener( 'keyup', keyup ); - - }; - - this.domElement.addEventListener( 'contextmenu', contextmenu ); - - this.domElement.addEventListener( 'pointerdown', onPointerDown ); - this.domElement.addEventListener( 'pointercancel', onPointerCancel ); - this.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } ); - - - window.addEventListener( 'keydown', keydown ); - window.addEventListener( 'keyup', keyup ); - - this.handleResize(); - - // force an update at start - this.update(); - - } - - } - - var colorScale$1={ - "jet":[{"index":0,"rgb":[0,0,131]},{"index":0.125,"rgb":[0,60,170]},{"index":0.375,"rgb":[5,255,255]},{"index":0.625,"rgb":[255,255,0]},{"index":0.875,"rgb":[250,0,0]},{"index":1,"rgb":[128,0,0]}], - - "hsv":[{"index":0,"rgb":[255,0,0]},{"index":0.169,"rgb":[253,255,2]},{"index":0.173,"rgb":[247,255,2]},{"index":0.337,"rgb":[0,252,4]},{"index":0.341,"rgb":[0,252,10]},{"index":0.506,"rgb":[1,249,255]},{"index":0.671,"rgb":[2,0,253]},{"index":0.675,"rgb":[8,0,253]},{"index":0.839,"rgb":[255,0,251]},{"index":0.843,"rgb":[255,0,245]},{"index":1,"rgb":[255,0,6]}], - - "hot":[{"index":0,"rgb":[0,0,0]},{"index":0.3,"rgb":[230,0,0]},{"index":0.6,"rgb":[255,210,0]},{"index":1,"rgb":[255,255,255]}], - - "spring":[{"index":0,"rgb":[255,0,255]},{"index":1,"rgb":[255,255,0]}], - - "summer":[{"index":0,"rgb":[0,128,102]},{"index":1,"rgb":[255,255,102]}], - - "autumn":[{"index":0,"rgb":[255,0,0]},{"index":1,"rgb":[255,255,0]}], - - "winter":[{"index":0,"rgb":[0,0,255]},{"index":1,"rgb":[0,255,128]}], - - "bone":[{"index":0,"rgb":[0,0,0]},{"index":0.376,"rgb":[84,84,116]},{"index":0.753,"rgb":[169,200,200]},{"index":1,"rgb":[255,255,255]}], - - "copper":[{"index":0,"rgb":[0,0,0]},{"index":0.804,"rgb":[255,160,102]},{"index":1,"rgb":[255,199,127]}], - - "greys":[{"index":0,"rgb":[0,0,0]},{"index":1,"rgb":[255,255,255]}], - - "yignbu":[{"index":0,"rgb":[8,29,88]},{"index":0.125,"rgb":[37,52,148]},{"index":0.25,"rgb":[34,94,168]},{"index":0.375,"rgb":[29,145,192]},{"index":0.5,"rgb":[65,182,196]},{"index":0.625,"rgb":[127,205,187]},{"index":0.75,"rgb":[199,233,180]},{"index":0.875,"rgb":[237,248,217]},{"index":1,"rgb":[255,255,217]}], - - "greens":[{"index":0,"rgb":[0,68,27]},{"index":0.125,"rgb":[0,109,44]},{"index":0.25,"rgb":[35,139,69]},{"index":0.375,"rgb":[65,171,93]},{"index":0.5,"rgb":[116,196,118]},{"index":0.625,"rgb":[161,217,155]},{"index":0.75,"rgb":[199,233,192]},{"index":0.875,"rgb":[229,245,224]},{"index":1,"rgb":[247,252,245]}], - - "yiorrd":[{"index":0,"rgb":[128,0,38]},{"index":0.125,"rgb":[189,0,38]},{"index":0.25,"rgb":[227,26,28]},{"index":0.375,"rgb":[252,78,42]},{"index":0.5,"rgb":[253,141,60]},{"index":0.625,"rgb":[254,178,76]},{"index":0.75,"rgb":[254,217,118]},{"index":0.875,"rgb":[255,237,160]},{"index":1,"rgb":[255,255,204]}], - - "bluered":[{"index":0,"rgb":[0,0,255]},{"index":1,"rgb":[255,0,0]}], - - "rdbu":[{"index":0,"rgb":[5,10,172]},{"index":0.35,"rgb":[106,137,247]},{"index":0.5,"rgb":[190,190,190]},{"index":0.6,"rgb":[220,170,132]},{"index":0.7,"rgb":[230,145,90]},{"index":1,"rgb":[178,10,28]}], - - "picnic":[{"index":0,"rgb":[0,0,255]},{"index":0.1,"rgb":[51,153,255]},{"index":0.2,"rgb":[102,204,255]},{"index":0.3,"rgb":[153,204,255]},{"index":0.4,"rgb":[204,204,255]},{"index":0.5,"rgb":[255,255,255]},{"index":0.6,"rgb":[255,204,255]},{"index":0.7,"rgb":[255,153,255]},{"index":0.8,"rgb":[255,102,204]},{"index":0.9,"rgb":[255,102,102]},{"index":1,"rgb":[255,0,0]}], - - "rainbow":[{"index":0,"rgb":[150,0,90]},{"index":0.125,"rgb":[0,0,200]},{"index":0.25,"rgb":[0,25,255]},{"index":0.375,"rgb":[0,152,255]},{"index":0.5,"rgb":[44,255,150]},{"index":0.625,"rgb":[151,255,0]},{"index":0.75,"rgb":[255,234,0]},{"index":0.875,"rgb":[255,111,0]},{"index":1,"rgb":[255,0,0]}], - - "portland":[{"index":0,"rgb":[12,51,131]},{"index":0.25,"rgb":[10,136,186]},{"index":0.5,"rgb":[242,211,56]},{"index":0.75,"rgb":[242,143,56]},{"index":1,"rgb":[217,30,30]}], - - "blackbody":[{"index":0,"rgb":[0,0,0]},{"index":0.2,"rgb":[230,0,0]},{"index":0.4,"rgb":[230,210,0]},{"index":0.7,"rgb":[255,255,255]},{"index":1,"rgb":[160,200,255]}], - - "earth":[{"index":0,"rgb":[0,0,130]},{"index":0.1,"rgb":[0,180,180]},{"index":0.2,"rgb":[40,210,40]},{"index":0.4,"rgb":[230,230,50]},{"index":0.6,"rgb":[120,70,20]},{"index":1,"rgb":[255,255,255]}], - - "electric":[{"index":0,"rgb":[0,0,0]},{"index":0.15,"rgb":[30,0,100]},{"index":0.4,"rgb":[120,0,100]},{"index":0.6,"rgb":[160,90,0]},{"index":0.8,"rgb":[230,200,0]},{"index":1,"rgb":[255,250,220]}], - - "alpha": [{"index":0, "rgb": [255,255,255,0]},{"index":1, "rgb": [255,255,255,1]}], - - "viridis": [{"index":0,"rgb":[68,1,84]},{"index":0.13,"rgb":[71,44,122]},{"index":0.25,"rgb":[59,81,139]},{"index":0.38,"rgb":[44,113,142]},{"index":0.5,"rgb":[33,144,141]},{"index":0.63,"rgb":[39,173,129]},{"index":0.75,"rgb":[92,200,99]},{"index":0.88,"rgb":[170,220,50]},{"index":1,"rgb":[253,231,37]}], - - "inferno": [{"index":0,"rgb":[0,0,4]},{"index":0.13,"rgb":[31,12,72]},{"index":0.25,"rgb":[85,15,109]},{"index":0.38,"rgb":[136,34,106]},{"index":0.5,"rgb":[186,54,85]},{"index":0.63,"rgb":[227,89,51]},{"index":0.75,"rgb":[249,140,10]},{"index":0.88,"rgb":[249,201,50]},{"index":1,"rgb":[252,255,164]}], - - "magma": [{"index":0,"rgb":[0,0,4]},{"index":0.13,"rgb":[28,16,68]},{"index":0.25,"rgb":[79,18,123]},{"index":0.38,"rgb":[129,37,129]},{"index":0.5,"rgb":[181,54,122]},{"index":0.63,"rgb":[229,80,100]},{"index":0.75,"rgb":[251,135,97]},{"index":0.88,"rgb":[254,194,135]},{"index":1,"rgb":[252,253,191]}], - - "plasma": [{"index":0,"rgb":[13,8,135]},{"index":0.13,"rgb":[75,3,161]},{"index":0.25,"rgb":[125,3,168]},{"index":0.38,"rgb":[168,34,150]},{"index":0.5,"rgb":[203,70,121]},{"index":0.63,"rgb":[229,107,93]},{"index":0.75,"rgb":[248,148,65]},{"index":0.88,"rgb":[253,195,40]},{"index":1,"rgb":[240,249,33]}], - - "warm": [{"index":0,"rgb":[125,0,179]},{"index":0.13,"rgb":[172,0,187]},{"index":0.25,"rgb":[219,0,170]},{"index":0.38,"rgb":[255,0,130]},{"index":0.5,"rgb":[255,63,74]},{"index":0.63,"rgb":[255,123,0]},{"index":0.75,"rgb":[234,176,0]},{"index":0.88,"rgb":[190,228,0]},{"index":1,"rgb":[147,255,0]}], - - "cool": [{"index":0,"rgb":[125,0,179]},{"index":0.13,"rgb":[116,0,218]},{"index":0.25,"rgb":[98,74,237]},{"index":0.38,"rgb":[68,146,231]},{"index":0.5,"rgb":[0,204,197]},{"index":0.63,"rgb":[0,247,146]},{"index":0.75,"rgb":[0,255,88]},{"index":0.88,"rgb":[40,255,8]},{"index":1,"rgb":[147,255,0]}], - - "rainbow-soft": [{"index":0,"rgb":[125,0,179]},{"index":0.1,"rgb":[199,0,180]},{"index":0.2,"rgb":[255,0,121]},{"index":0.3,"rgb":[255,108,0]},{"index":0.4,"rgb":[222,194,0]},{"index":0.5,"rgb":[150,255,0]},{"index":0.6,"rgb":[0,255,55]},{"index":0.7,"rgb":[0,246,150]},{"index":0.8,"rgb":[50,167,222]},{"index":0.9,"rgb":[103,51,235]},{"index":1,"rgb":[124,0,186]}], - - "bathymetry": [{"index":0,"rgb":[40,26,44]},{"index":0.13,"rgb":[59,49,90]},{"index":0.25,"rgb":[64,76,139]},{"index":0.38,"rgb":[63,110,151]},{"index":0.5,"rgb":[72,142,158]},{"index":0.63,"rgb":[85,174,163]},{"index":0.75,"rgb":[120,206,163]},{"index":0.88,"rgb":[187,230,172]},{"index":1,"rgb":[253,254,204]}], - - "cdom": [{"index":0,"rgb":[47,15,62]},{"index":0.13,"rgb":[87,23,86]},{"index":0.25,"rgb":[130,28,99]},{"index":0.38,"rgb":[171,41,96]},{"index":0.5,"rgb":[206,67,86]},{"index":0.63,"rgb":[230,106,84]},{"index":0.75,"rgb":[242,149,103]},{"index":0.88,"rgb":[249,193,135]},{"index":1,"rgb":[254,237,176]}], - - "chlorophyll": [{"index":0,"rgb":[18,36,20]},{"index":0.13,"rgb":[25,63,41]},{"index":0.25,"rgb":[24,91,59]},{"index":0.38,"rgb":[13,119,72]},{"index":0.5,"rgb":[18,148,80]},{"index":0.63,"rgb":[80,173,89]},{"index":0.75,"rgb":[132,196,122]},{"index":0.88,"rgb":[175,221,162]},{"index":1,"rgb":[215,249,208]}], - - "density": [{"index":0,"rgb":[54,14,36]},{"index":0.13,"rgb":[89,23,80]},{"index":0.25,"rgb":[110,45,132]},{"index":0.38,"rgb":[120,77,178]},{"index":0.5,"rgb":[120,113,213]},{"index":0.63,"rgb":[115,151,228]},{"index":0.75,"rgb":[134,185,227]},{"index":0.88,"rgb":[177,214,227]},{"index":1,"rgb":[230,241,241]}], - - "freesurface-blue": [{"index":0,"rgb":[30,4,110]},{"index":0.13,"rgb":[47,14,176]},{"index":0.25,"rgb":[41,45,236]},{"index":0.38,"rgb":[25,99,212]},{"index":0.5,"rgb":[68,131,200]},{"index":0.63,"rgb":[114,156,197]},{"index":0.75,"rgb":[157,181,203]},{"index":0.88,"rgb":[200,208,216]},{"index":1,"rgb":[241,237,236]}], - - "freesurface-red": [{"index":0,"rgb":[60,9,18]},{"index":0.13,"rgb":[100,17,27]},{"index":0.25,"rgb":[142,20,29]},{"index":0.38,"rgb":[177,43,27]},{"index":0.5,"rgb":[192,87,63]},{"index":0.63,"rgb":[205,125,105]},{"index":0.75,"rgb":[216,162,148]},{"index":0.88,"rgb":[227,199,193]},{"index":1,"rgb":[241,237,236]}], - - "oxygen": [{"index":0,"rgb":[64,5,5]},{"index":0.13,"rgb":[106,6,15]},{"index":0.25,"rgb":[144,26,7]},{"index":0.38,"rgb":[168,64,3]},{"index":0.5,"rgb":[188,100,4]},{"index":0.63,"rgb":[206,136,11]},{"index":0.75,"rgb":[220,174,25]},{"index":0.88,"rgb":[231,215,44]},{"index":1,"rgb":[248,254,105]}], - - "par": [{"index":0,"rgb":[51,20,24]},{"index":0.13,"rgb":[90,32,35]},{"index":0.25,"rgb":[129,44,34]},{"index":0.38,"rgb":[159,68,25]},{"index":0.5,"rgb":[182,99,19]},{"index":0.63,"rgb":[199,134,22]},{"index":0.75,"rgb":[212,171,35]},{"index":0.88,"rgb":[221,210,54]},{"index":1,"rgb":[225,253,75]}], - - "phase": [{"index":0,"rgb":[145,105,18]},{"index":0.13,"rgb":[184,71,38]},{"index":0.25,"rgb":[186,58,115]},{"index":0.38,"rgb":[160,71,185]},{"index":0.5,"rgb":[110,97,218]},{"index":0.63,"rgb":[50,123,164]},{"index":0.75,"rgb":[31,131,110]},{"index":0.88,"rgb":[77,129,34]},{"index":1,"rgb":[145,105,18]}], - - "salinity": [{"index":0,"rgb":[42,24,108]},{"index":0.13,"rgb":[33,50,162]},{"index":0.25,"rgb":[15,90,145]},{"index":0.38,"rgb":[40,118,137]},{"index":0.5,"rgb":[59,146,135]},{"index":0.63,"rgb":[79,175,126]},{"index":0.75,"rgb":[120,203,104]},{"index":0.88,"rgb":[193,221,100]},{"index":1,"rgb":[253,239,154]}], - - "temperature": [{"index":0,"rgb":[4,35,51]},{"index":0.13,"rgb":[23,51,122]},{"index":0.25,"rgb":[85,59,157]},{"index":0.38,"rgb":[129,79,143]},{"index":0.5,"rgb":[175,95,130]},{"index":0.63,"rgb":[222,112,101]},{"index":0.75,"rgb":[249,146,66]},{"index":0.88,"rgb":[249,196,65]},{"index":1,"rgb":[232,250,91]}], - - "turbidity": [{"index":0,"rgb":[34,31,27]},{"index":0.13,"rgb":[65,50,41]},{"index":0.25,"rgb":[98,69,52]},{"index":0.38,"rgb":[131,89,57]},{"index":0.5,"rgb":[161,112,59]},{"index":0.63,"rgb":[185,140,66]},{"index":0.75,"rgb":[202,174,88]},{"index":0.88,"rgb":[216,209,126]},{"index":1,"rgb":[233,246,171]}], - - "velocity-blue": [{"index":0,"rgb":[17,32,64]},{"index":0.13,"rgb":[35,52,116]},{"index":0.25,"rgb":[29,81,156]},{"index":0.38,"rgb":[31,113,162]},{"index":0.5,"rgb":[50,144,169]},{"index":0.63,"rgb":[87,173,176]},{"index":0.75,"rgb":[149,196,189]},{"index":0.88,"rgb":[203,221,211]},{"index":1,"rgb":[254,251,230]}], - - "velocity-green": [{"index":0,"rgb":[23,35,19]},{"index":0.13,"rgb":[24,64,38]},{"index":0.25,"rgb":[11,95,45]},{"index":0.38,"rgb":[39,123,35]},{"index":0.5,"rgb":[95,146,12]},{"index":0.63,"rgb":[152,165,18]},{"index":0.75,"rgb":[201,186,69]},{"index":0.88,"rgb":[233,216,137]},{"index":1,"rgb":[255,253,205]}], - - "cubehelix": [{"index":0,"rgb":[0,0,0]},{"index":0.07,"rgb":[22,5,59]},{"index":0.13,"rgb":[60,4,105]},{"index":0.2,"rgb":[109,1,135]},{"index":0.27,"rgb":[161,0,147]},{"index":0.33,"rgb":[210,2,142]},{"index":0.4,"rgb":[251,11,123]},{"index":0.47,"rgb":[255,29,97]},{"index":0.53,"rgb":[255,54,69]},{"index":0.6,"rgb":[255,85,46]},{"index":0.67,"rgb":[255,120,34]},{"index":0.73,"rgb":[255,157,37]},{"index":0.8,"rgb":[241,191,57]},{"index":0.87,"rgb":[224,220,93]},{"index":0.93,"rgb":[218,241,142]},{"index":1,"rgb":[227,253,198]}] - }; - - function lerp$1(v0, v1, t) { - return v0*(1-t)+v1*t - } - var lerp_1 = lerp$1; - - /* - * Ben Postlethwaite - * January 2013 - * License MIT - */ - - var colorScale = colorScale$1; - var lerp = lerp_1; - - var colormap = createColormap; - - function createColormap (spec) { - /* - * Default Options - */ - var indicies, fromrgba, torgba, - nsteps, cmap, colormap, format, - nshades, colors, alpha, i; - - if ( !spec ) spec = {}; - - nshades = (spec.nshades || 72) - 1; - format = spec.format || 'hex'; - - colormap = spec.colormap; - if (!colormap) colormap = 'jet'; - - if (typeof colormap === 'string') { - colormap = colormap.toLowerCase(); - - if (!colorScale[colormap]) { - throw Error(colormap + ' not a supported colorscale'); - } - - cmap = colorScale[colormap]; - - } else if (Array.isArray(colormap)) { - cmap = colormap.slice(); - - } else { - throw Error('unsupported colormap option', colormap); - } - - if (cmap.length > nshades + 1) { - throw new Error( - colormap+' map requires nshades to be at least size '+cmap.length - ); - } - - if (!Array.isArray(spec.alpha)) { - - if (typeof spec.alpha === 'number') { - alpha = [spec.alpha, spec.alpha]; - - } else { - alpha = [1, 1]; - } - - } else if (spec.alpha.length !== 2) { - alpha = [1, 1]; - - } else { - alpha = spec.alpha.slice(); - } - - // map index points from 0..1 to 0..n-1 - indicies = cmap.map(function(c) { - return Math.round(c.index * nshades); - }); - - // Add alpha channel to the map - alpha[0] = Math.min(Math.max(alpha[0], 0), 1); - alpha[1] = Math.min(Math.max(alpha[1], 0), 1); - - var steps = cmap.map(function(c, i) { - var index = cmap[i].index; - - var rgba = cmap[i].rgb.slice(); - - // if user supplies their own map use it - if (rgba.length === 4 && rgba[3] >= 0 && rgba[3] <= 1) { - return rgba - } - rgba[3] = alpha[0] + (alpha[1] - alpha[0])*index; - - return rgba - }); - - - /* - * map increasing linear values between indicies to - * linear steps in colorvalues - */ - var colors = []; - for (i = 0; i < indicies.length-1; ++i) { - nsteps = indicies[i+1] - indicies[i]; - fromrgba = steps[i]; - torgba = steps[i+1]; - - for (var j = 0; j < nsteps; j++) { - var amt = j / nsteps; - colors.push([ - Math.round(lerp(fromrgba[0], torgba[0], amt)), - Math.round(lerp(fromrgba[1], torgba[1], amt)), - Math.round(lerp(fromrgba[2], torgba[2], amt)), - lerp(fromrgba[3], torgba[3], amt) - ]); - } - } - - //add 1 step as last value - colors.push(cmap[cmap.length - 1].rgb.concat(alpha[1])); - - if (format === 'hex') colors = colors.map( rgb2hex ); - else if (format === 'rgbaString') colors = colors.map( rgbaStr ); - else if (format === 'float') colors = colors.map( rgb2float ); - - return colors; - } - function rgb2float (rgba) { - return [ - rgba[0] / 255, - rgba[1] / 255, - rgba[2] / 255, - rgba[3] - ] - } - - function rgb2hex (rgba) { - var dig, hex = '#'; - for (var i = 0; i < 3; ++i) { - dig = rgba[i]; - dig = dig.toString(16); - hex += ('00' + dig).substr( dig.length ); - } - return hex; - } - - function rgbaStr (rgba) { - return 'rgba(' + rgba.join(',') + ')'; - } - - class EventEmitter { - constructor() { - this._events = {}; - } - - on(event, listener) { - if (!this._events[event]) { - this._events[event] = []; - } - this._events[event].push(listener); - return () => this.removeListener(event, listener); - } - - emit(event, ...args) { - if (this._events[event]) { - this._events[event].forEach((listener) => listener(...args)); - } - } - - removeListener(event, listenerToRemove) { - if (this._events[event]) { - this._events[event] = this._events[event].filter( - (listener) => listener !== listenerToRemove - ); - } - } - } - - class ColorMap$1 extends EventEmitter { - constructor(colors, options = {}) { - super(); - if (!Array.isArray(colors) || colors.length === 0) { - throw new TypeError('Colors must be a non-empty array'); - } - - this.colors = colors.map(color => this.parseColor(color)); - this._hasAlpha = this.colors[0].length === 4; - this.setRange(options.range); - this.setThreshold(options.threshold); - this.setAlpha(options.alpha); - } - - setRange(range) { - if (Array.isArray(range) && range.length === 2 && range.every(v => typeof v === 'number')) { - this.range = range; - console.log('ColorMap: Emitting rangeChanged event', this.range); - this.emit('rangeChanged', this.range); - } else { - this.range = [0, 1]; - } - } - - setThreshold(threshold) { - if (Array.isArray(threshold) && threshold.length === 2 && threshold.every(v => typeof v === 'number')) { - this.threshold = threshold; - console.log('ColorMap: Emitting thresholdChanged event', this.threshold); - this.emit('thresholdChanged', this.threshold); - } else { - this.threshold = [0, 0]; - } - } - - parseColor(color) { - if (typeof color === 'string' && color.startsWith('#')) { - return this.hexToRgb(color); - } - if (Array.isArray(color) && (color.length === 3 || color.length === 4) && color.every(v => typeof v === 'number')) { - return color; - } - throw new TypeError('Invalid color format'); - } - - hexToRgb(hex) { - // Remove the hash at the start if it's there - hex = hex.replace(/^#/, ''); - - // Parse the r, g, b values - const r = parseInt(hex.slice(0, 2), 16) / 255; - const g = parseInt(hex.slice(2, 4), 16) / 255; - const b = parseInt(hex.slice(4, 6), 16) / 255; - - // Check if there's an alpha channel - if (hex.length === 8) { - const a = parseInt(hex.slice(6, 8), 16) / 255; - return [r, g, b, a]; - } - - return [r, g, b]; - } - - setAlpha(alpha) { - if (alpha === undefined) { - this.colors = this.colors.map(color => color.length === 3 ? [...color, 1] : color); - } else if (typeof alpha === 'number' && alpha >= 0 && alpha <= 1) { - this.colors = this.colors.map(color => [...color.slice(0, 3), alpha]); - } else if (Array.isArray(alpha) && alpha.length === this.colors.length && alpha.every(v => typeof v === 'number' && v >= 0 && v <= 1)) { - this.colors = this.colors.map((color, i) => [...color.slice(0, 3), alpha[i]]); - } else { - throw new TypeError('Invalid alpha parameter'); - } - this._hasAlpha = true; - this.emit('alphaChanged', this._hasAlpha); - } - - getColor(value) { - if (typeof value !== 'number') { - throw new TypeError('Value must be a number'); - } - const [min, max] = this.range; - const [low, high] = this.threshold; - - // Apply threshold - if (value >= low && value <= high) { - return [0, 0, 0, 0]; // Fully transparent - } - - const normalizedValue = (value - min) / (max - min); - const index = Math.min(Math.max(Math.floor(normalizedValue * (this.colors.length - 1)), 0), this.colors.length - 1); - const color = this.colors[index]; - return color.length === 3 ? [...color, 1] : color; // Ensure returned color has alpha channel - } - - getColorArray(values) { - if (!(Array.isArray(values) || values instanceof Float32Array) || values.length === 0) { - throw new TypeError('Values must be a non-empty array or Float32Array'); - } - - const componentsPerColor = this.hasAlpha ? 4 : 3; - const colorArray = new Float32Array(values.length * componentsPerColor); - - for (let i = 0; i < values.length; i++) { - const color = this.getColor(values[i]); - const offset = i * componentsPerColor; - colorArray[offset] = color[0]; - colorArray[offset + 1] = color[1]; - colorArray[offset + 2] = color[2]; - if (this.hasAlpha) { - colorArray[offset + 3] = color[3]; - } - } - - return colorArray; - } - - getColors(values) { - if (!Array.isArray(values) || !values.every(v => typeof v === 'number')) { - throw new TypeError('Values must be an array of numbers'); - } - return values.map(this.getColor.bind(this)); - } - - get hasAlpha() { - return this._hasAlpha; - } - - static presetMaps = { - jet: ColorMap$1.generatePreset('jet'), - density: ColorMap$1.generatePreset('density'), - freesurfaceBlue: ColorMap$1.generatePreset('freesurface-blue'), - freesurfaceRed: ColorMap$1.generatePreset('freesurface-red'), - oxygen: ColorMap$1.generatePreset('oxygen'), - par: ColorMap$1.generatePreset('par'), - phase: ColorMap$1.generatePreset('phase'), - salinity: ColorMap$1.generatePreset('salinity'), - temperature: ColorMap$1.generatePreset('temperature'), - turbidity: ColorMap$1.generatePreset('turbidity'), - velocityBlue: ColorMap$1.generatePreset('velocity-blue'), - velocityGreen: ColorMap$1.generatePreset('velocity-green'), - cubehelix: ColorMap$1.generatePreset('cubehelix') - }; - - static generatePreset(name) { - return colormap({ - colormap: name, - nshades: 256, - format: 'hex', - alpha: 1 - }); - } - - static getAvailableMaps() { - return Object.keys(ColorMap$1.presetMaps); - } - - static fromPreset(name, options = {}) { - if (!ColorMap$1.presetMaps.hasOwnProperty(name)) { - throw new Error(`Preset "${name}" not found`); - } - const presetColors = ColorMap$1.presetMaps[name]; - - if (options.existingColorMap instanceof ColorMap$1) { - return options.existingColorMap.copy(presetColors); - } - - return new ColorMap$1(presetColors, options); - } - - copy(newColors) { - const options = { - range: this.range, - threshold: this.threshold, - alpha: this._hasAlpha ? this.colors.map(color => color[3]) : undefined - }; - - return new ColorMap$1(newColors, options); - } - } - - class SurfaceGeometry { - constructor(vertices, faces, hemi) { - this.vertices = new Float32Array(vertices); - this.faces = new Uint32Array(faces); - this.hemi = hemi; - this.mesh = null; - - console.log("SurfaceGeometry constructor called"); - console.log("Vertices:", this.vertices.length); - console.log("Faces:", this.faces.length); - console.log("Hemi:", this.hemi); - - this.createMesh(); - } - - createMesh() { - const geometry = new BufferGeometry(); - geometry.setAttribute('position', new Float32BufferAttribute(this.vertices, 3)); - geometry.setIndex(new Uint32BufferAttribute(this.faces, 1)); - - const material = new MeshPhongMaterial({ - color: 0xA9A9A9, // Set default color to dark gray - flatShading: false, - vertexColors: false - }); - - this.mesh = new Mesh(geometry, material); - console.log("SurfaceGeometry construction complete"); - console.log("Mesh:", this.mesh); - } - } - - class NeuroSurface { - constructor(geometry, indices, data, config = {}) { - this.geometry = geometry; - this.indices = new Uint32Array(indices); - this.data = new Float32Array(data); - this.mesh = null; - this.threshold = config.thresh || [0, 0]; - this.irange = config.irange || [Math.min(...data), Math.max(...data)]; - - this.config = { - color: new Color(0xA9A9A9), // Set default color to dark gray - flatShading: false, - shininess: 30, - specularColor: 0x111111, - alpha: 1, - ...config - }; - } - - update(property, value) { - const methodName = `update${property.charAt(0).toUpperCase() + property.slice(1)}`; - if (this[methodName]) { - this[methodName](value); - } else { - console.warn(`Update method for ${property} not implemented in ${this.constructor.name}`); - } - } - - updateConfig(newConfig) { - this.config = { ...this.config, ...newConfig }; - if (this.mesh) { - Object.assign(this.mesh.material, { - color: this.config.color, - specular: this.config.specularColor, - shininess: this.config.shininess, - flatShading: this.config.flatShading, - transparent: this.config.alpha < 1, - opacity: this.config.alpha - }); - this.mesh.material.needsUpdate = true; - } - } - - mapValueToColor(value) { - if (value > this.threshold[0] && value < this.threshold[1]) { - return new Color(0, 0, 0, 0); // Return transparent for values within the threshold - } - - const normalizedValue = (value - this.irange[0]) / (this.irange[1] - this.irange[0]); - const index = Math.min(Math.floor(normalizedValue * (this.colorMap.length - 1)), this.colorMap.length - 1); - return this.colorMap[index]; - } - - createMesh() { - const geometry = new BufferGeometry(); - geometry.setAttribute('position', new Float32BufferAttribute(this.geometry.vertices, 3)); - geometry.setIndex(new Uint32BufferAttribute(this.geometry.faces, 1)); - - const material = new MeshBasicMaterial({ - vertexColors: true // Will be set to true for colored surfaces - }); - - this.mesh = new Mesh(geometry, material); - this.updateColors(); - return this.mesh; - } - - updateMesh() { - if (!this.mesh) { - return this.createMesh(); - } - this.mesh.geometry.attributes.position.needsUpdate = true; - this.mesh.geometry.index.needsUpdate = true; - return this.mesh; - } - - updateColors() { - if (!this.mesh || !this.colorMap) { - console.warn('Mesh or ColorMap not initialized in updateColors'); - return; - } - - const vertexCount = this.geometry.vertices.length / 3; - const componentsPerColor = this.colorMap.hasAlpha ? 4 : 3; - const colors = new Float32Array(vertexCount * componentsPerColor); - - if (this.config.alpha > 0) { - if (!this.data) { - console.error('Data not initialized in updateColors'); - return; - } - - const mappedColors = this.colorMap.getColorArray(this.data); - - for (let i = 0; i < this.indices.length; i++) { - const index = this.indices[i]; - const colorIndex = index * componentsPerColor; - for (let j = 0; j < componentsPerColor; j++) { - colors[colorIndex + j] = mappedColors[colorIndex + j]; - } - } - } else { - // When alpha is 0, use the default color for all vertices - const defaultColor = new Color(this.config.color); - for (let i = 0; i < colors.length; i += componentsPerColor) { - colors[i] = defaultColor.r; - colors[i + 1] = defaultColor.g; - colors[i + 2] = defaultColor.b; - if (componentsPerColor === 4) { - colors[i + 3] = 1; // Full opacity when alpha is 0 - } - } - } - - this.mesh.geometry.setAttribute('color', new BufferAttribute(colors, componentsPerColor)); - this.mesh.geometry.attributes.color.needsUpdate = true; - this.mesh.material.vertexColors = true; - this.mesh.material.transparent = this.colorMap.hasAlpha; - this.mesh.material.needsUpdate = true; - } - } - - class ColorMappedNeuroSurface extends NeuroSurface { - constructor(geometry, indices, data, colorMap, config = {}) { - super(geometry, indices, data, config); - - this.colorMap = null; - this.rangeListener = null; - this.thresholdListener = null; - this.alphaListener = null; - - this.createMesh(); // Create the mesh first - this.setColorMap(colorMap); // Set the color map and update colors - } - - setColorMap(colorMap) { - if (this.colorMap) { - // Remove old listeners - this.rangeListener(); - this.thresholdListener(); - this.alphaListener(); - } - - if (!(colorMap instanceof ColorMap$1)) { - if (typeof colorMap === 'string') { - this.colorMap = ColorMap$1.fromPreset(colorMap); - } else if (Array.isArray(colorMap)) { - this.colorMap = new ColorMap$1(colorMap); - } else { - console.error('Invalid colorMap provided. Using default.'); - this.colorMap = ColorMap$1.fromPreset('jet'); - } - } else { - this.colorMap = colorMap; - } - - this.colorMap.setThreshold(this.threshold); - this.colorMap.setRange(this.irange); - this.colorMap.setAlpha(this.config.alpha); - - // Set up new listeners - this.rangeListener = this.colorMap.on('rangeChanged', (range) => { - console.log('ColorMappedNeuroSurface: Received rangeChanged event', range); - this.irange = range; - this.updateColors(); - }); - this.thresholdListener = this.colorMap.on('thresholdChanged', (threshold) => { - console.log('ColorMappedNeuroSurface: Received thresholdChanged event', threshold); - this.threshold = threshold; - this.updateColors(); - }); - this.alphaListener = this.colorMap.on('alphaChanged', (alpha) => { - console.log('ColorMappedNeuroSurface: Received alphaChanged event', alpha); - this.config.alpha = alpha; - this.updateColors(); - }); - - if (this.mesh) { - this.updateColors(); - } - } - - createMesh() { - const geometry = new BufferGeometry(); - geometry.setAttribute('position', new Float32BufferAttribute(this.geometry.vertices, 3)); - geometry.setIndex(new Uint32BufferAttribute(this.geometry.faces, 1)); - - // Use MeshPhongMaterial for better shading - const material = new MeshPhongMaterial({ - vertexColors: true, - transparent: true, - opacity: this.config.alpha, - shininess: this.config.shininess || 30, - specular: new Color(this.config.specularColor || 0x111111), - flatShading: this.config.flatShading || false - }); - - this.mesh = new Mesh(geometry, material); - - // Compute vertex normals for better lighting - geometry.computeVertexNormals(); - - return this.mesh; - } - - updateColors() { - console.log('Updating colors. Mesh:', !!this.mesh, 'ColorMap:', !!this.colorMap); - if (!this.mesh || !this.colorMap) { - console.warn('Mesh or ColorMap not initialized in updateColors'); - console.log('Mesh:', this.mesh); - console.log('ColorMap:', this.colorMap); - return; - } - - const vertexCount = this.geometry.vertices.length / 3; - const componentsPerColor = 4; // Always use RGBA - const colors = new Float32Array(vertexCount * componentsPerColor); - - console.log("threshold", this.threshold); - console.log("irange", this.irange); - console.log("alpha", this.config.alpha); - console.log("data", this.data); - - const baseSurfaceColor = new Color(this.config.color); - - if (this.data) { - for (let i = 0; i < this.indices.length; i++) { - const index = this.indices[i]; - const value = this.data[i]; - const color = this.colorMap.getColor(value); - const colorIndex = index * componentsPerColor; - - if (value >= this.threshold[0] && value <= this.threshold[1]) { - // Use opaque base color when value is within threshold - colors[colorIndex] = baseSurfaceColor.r; - colors[colorIndex + 1] = baseSurfaceColor.g; - colors[colorIndex + 2] = baseSurfaceColor.b; - colors[colorIndex + 3] = 1; // Fully opaque - } else { - // Blend with base surface color based on alpha - const overlayAlpha = color[3] * this.config.alpha; - colors[colorIndex] = overlayAlpha * color[0] + (1 - overlayAlpha) * baseSurfaceColor.r; - colors[colorIndex + 1] = overlayAlpha * color[1] + (1 - overlayAlpha) * baseSurfaceColor.g; - colors[colorIndex + 2] = overlayAlpha * color[2] + (1 - overlayAlpha) * baseSurfaceColor.b; - colors[colorIndex + 3] = 1; // Always opaque - } - } - } else { - // When no data, use the opaque default color for all vertices - for (let i = 0; i < colors.length; i += componentsPerColor) { - colors[i] = baseSurfaceColor.r; - colors[i + 1] = baseSurfaceColor.g; - colors[i + 2] = baseSurfaceColor.b; - colors[i + 3] = 1; // Fully opaque - } - } - - this.mesh.geometry.setAttribute('color', new BufferAttribute(colors, componentsPerColor)); - this.mesh.geometry.attributes.color.needsUpdate = true; - this.mesh.material.vertexColors = true; - this.mesh.material.needsUpdate = true; - - // Ensure transparency is set correctly - this.mesh.material.transparent = true; - this.mesh.material.opacity = 1; // We're using per-vertex color blending now - } - - updateConfig(newConfig) { - super.updateConfig(newConfig); - if (this.mesh && this.mesh.material) { - this.mesh.material.shininess = this.config.shininess || 30; - this.mesh.material.specular = new Color(this.config.specularColor || 0x111111); - this.mesh.material.flatShading = this.config.flatShading || false; - this.mesh.material.needsUpdate = true; - } - if (this.colorMap) { - this.colorMap.setAlpha(this.config.alpha); - } - this.updateColors(); // Reapply colors with new config - } - - setData(newData) { - if (newData.length !== this.data.length) { - console.error('New data length does not match the current data length'); - return; - } - this.data = newData; - this.updateColors(); - } - } - - class VertexColoredNeuroSurface extends NeuroSurface { - constructor(geometry, indices, colors, config = {}) { - super(geometry, indices, new Float32Array(indices.length), config); - this.setColors(colors); - } - - setColors(newColors) { - this.colors = new Float32Array(newColors.length * 3); - for (let i = 0; i < newColors.length; i++) { - const color = new Color(newColors[i]); - this.colors[i * 3] = color.r; - this.colors[i * 3 + 1] = color.g; - this.colors[i * 3 + 2] = color.b; - } - this.updateColors(); - } - - updateColors() { - if (!this.mesh) return; - - const colors = new Float32Array(this.geometry.vertices.length); - for (let i = 0; i < this.indices.length; i++) { - const index = this.indices[i]; - colors[index * 3] = this.colors[i * 3]; - colors[index * 3 + 1] = this.colors[i * 3 + 1]; - colors[index * 3 + 2] = this.colors[i * 3 + 2]; - } - - this.mesh.geometry.setAttribute('color', new BufferAttribute(colors, 3)); - this.mesh.geometry.attributes.color.needsUpdate = true; - this.mesh.material.vertexColors = true; - this.mesh.material.needsUpdate = true; - } - - createMesh() { - const mesh = super.createMesh(); - mesh.material.vertexColors = true; - this.updateColors(); - return mesh; - } - } - - /*! Tweakpane 4.0.4 (c) 2016 cocopon, licensed under the MIT license. */ - function forceCast$1(v) { - return v; - } - function isEmpty$1(value) { - return value === null || value === undefined; - } - function isObject$1$1(value) { - return value !== null && typeof value === 'object'; - } - function isRecord$1(value) { - return value !== null && typeof value === 'object'; - } - function deepEqualsArray$1(a1, a2) { - if (a1.length !== a2.length) { - return false; - } - for (let i = 0; i < a1.length; i++) { - if (a1[i] !== a2[i]) { - return false; - } - } - return true; - } - function deepMerge$1(r1, r2) { - const keys = Array.from(new Set([...Object.keys(r1), ...Object.keys(r2)])); - return keys.reduce((result, key) => { - const v1 = r1[key]; - const v2 = r2[key]; - return isRecord$1(v1) && isRecord$1(v2) - ? Object.assign(Object.assign({}, result), { [key]: deepMerge$1(v1, v2) }) : Object.assign(Object.assign({}, result), { [key]: key in r2 ? v2 : v1 }); - }, {}); - } - - function isBinding$1(value) { - if (!isObject$1$1(value)) { - return false; - } - return 'target' in value; - } - - const CREATE_MESSAGE_MAP$1 = { - alreadydisposed: () => 'View has been already disposed', - invalidparams: (context) => `Invalid parameters for '${context.name}'`, - nomatchingcontroller: (context) => `No matching controller for '${context.key}'`, - nomatchingview: (context) => `No matching view for '${JSON.stringify(context.params)}'`, - notbindable: () => `Value is not bindable`, - notcompatible: (context) => `Not compatible with plugin '${context.id}'`, - propertynotfound: (context) => `Property '${context.name}' not found`, - shouldneverhappen: () => 'This error should never happen', - }; - class TpError$1 { - static alreadyDisposed() { - return new TpError$1({ type: 'alreadydisposed' }); - } - static notBindable() { - return new TpError$1({ - type: 'notbindable', - }); - } - static notCompatible(bundleId, id) { - return new TpError$1({ - type: 'notcompatible', - context: { - id: `${bundleId}.${id}`, - }, - }); - } - static propertyNotFound(name) { - return new TpError$1({ - type: 'propertynotfound', - context: { - name: name, - }, - }); - } - static shouldNeverHappen() { - return new TpError$1({ type: 'shouldneverhappen' }); - } - constructor(config) { - var _a; - this.message = - (_a = CREATE_MESSAGE_MAP$1[config.type](forceCast$1(config.context))) !== null && _a !== void 0 ? _a : 'Unexpected error'; - this.name = this.constructor.name; - this.stack = new Error(this.message).stack; - this.type = config.type; - } - toString() { - return this.message; - } - } - - class BindingTarget$1 { - constructor(obj, key) { - this.obj_ = obj; - this.key = key; - } - static isBindable(obj) { - if (obj === null) { - return false; - } - if (typeof obj !== 'object' && typeof obj !== 'function') { - return false; - } - return true; - } - read() { - return this.obj_[this.key]; - } - write(value) { - this.obj_[this.key] = value; - } - writeProperty(name, value) { - const valueObj = this.read(); - if (!BindingTarget$1.isBindable(valueObj)) { - throw TpError$1.notBindable(); - } - if (!(name in valueObj)) { - throw TpError$1.propertyNotFound(name); - } - valueObj[name] = value; - } - } - - class Emitter$1 { - constructor() { - this.observers_ = {}; - } - on(eventName, handler, opt_options) { - var _a; - let observers = this.observers_[eventName]; - if (!observers) { - observers = this.observers_[eventName] = []; - } - observers.push({ - handler: handler, - key: (_a = opt_options === null || opt_options === void 0 ? void 0 : opt_options.key) !== null && _a !== void 0 ? _a : handler, - }); - return this; - } - off(eventName, key) { - const observers = this.observers_[eventName]; - if (observers) { - this.observers_[eventName] = observers.filter((observer) => { - return observer.key !== key; - }); - } - return this; - } - emit(eventName, event) { - const observers = this.observers_[eventName]; - if (!observers) { - return; - } - observers.forEach((observer) => { - observer.handler(event); - }); - } - } - - class ComplexValue$1 { - constructor(initialValue, config) { - var _a; - this.constraint_ = config === null || config === void 0 ? void 0 : config.constraint; - this.equals_ = (_a = config === null || config === void 0 ? void 0 : config.equals) !== null && _a !== void 0 ? _a : ((v1, v2) => v1 === v2); - this.emitter = new Emitter$1(); - this.rawValue_ = initialValue; - } - get constraint() { - return this.constraint_; - } - get rawValue() { - return this.rawValue_; - } - set rawValue(rawValue) { - this.setRawValue(rawValue, { - forceEmit: false, - last: true, - }); - } - setRawValue(rawValue, options) { - const opts = options !== null && options !== void 0 ? options : { - forceEmit: false, - last: true, - }; - const constrainedValue = this.constraint_ - ? this.constraint_.constrain(rawValue) - : rawValue; - const prevValue = this.rawValue_; - const changed = !this.equals_(prevValue, constrainedValue); - if (!changed && !opts.forceEmit) { - return; - } - this.emitter.emit('beforechange', { - sender: this, - }); - this.rawValue_ = constrainedValue; - this.emitter.emit('change', { - options: opts, - previousRawValue: prevValue, - rawValue: constrainedValue, - sender: this, - }); - } - } - - class PrimitiveValue$1 { - constructor(initialValue) { - this.emitter = new Emitter$1(); - this.value_ = initialValue; - } - get rawValue() { - return this.value_; - } - set rawValue(value) { - this.setRawValue(value, { - forceEmit: false, - last: true, - }); - } - setRawValue(value, options) { - const opts = options !== null && options !== void 0 ? options : { - forceEmit: false, - last: true, - }; - const prevValue = this.value_; - if (prevValue === value && !opts.forceEmit) { - return; - } - this.emitter.emit('beforechange', { - sender: this, - }); - this.value_ = value; - this.emitter.emit('change', { - options: opts, - previousRawValue: prevValue, - rawValue: this.value_, - sender: this, - }); - } - } - - class ReadonlyPrimitiveValue$1 { - constructor(value) { - this.emitter = new Emitter$1(); - this.onValueBeforeChange_ = this.onValueBeforeChange_.bind(this); - this.onValueChange_ = this.onValueChange_.bind(this); - this.value_ = value; - this.value_.emitter.on('beforechange', this.onValueBeforeChange_); - this.value_.emitter.on('change', this.onValueChange_); - } - get rawValue() { - return this.value_.rawValue; - } - onValueBeforeChange_(ev) { - this.emitter.emit('beforechange', Object.assign(Object.assign({}, ev), { sender: this })); - } - onValueChange_(ev) { - this.emitter.emit('change', Object.assign(Object.assign({}, ev), { sender: this })); - } - } - - function createValue$1(initialValue, config) { - const constraint = config === null || config === void 0 ? void 0 : config.constraint; - const equals = config === null || config === void 0 ? void 0 : config.equals; - if (!constraint && !equals) { - return new PrimitiveValue$1(initialValue); - } - return new ComplexValue$1(initialValue, config); - } - function createReadonlyValue$1(value) { - return [ - new ReadonlyPrimitiveValue$1(value), - (rawValue, options) => { - value.setRawValue(rawValue, options); - }, - ]; - } - - class ValueMap$1 { - constructor(valueMap) { - this.emitter = new Emitter$1(); - this.valMap_ = valueMap; - for (const key in this.valMap_) { - const v = this.valMap_[key]; - v.emitter.on('change', () => { - this.emitter.emit('change', { - key: key, - sender: this, - }); - }); - } - } - static createCore(initialValue) { - const keys = Object.keys(initialValue); - return keys.reduce((o, key) => { - return Object.assign(o, { - [key]: createValue$1(initialValue[key]), - }); - }, {}); - } - static fromObject(initialValue) { - const core = this.createCore(initialValue); - return new ValueMap$1(core); - } - get(key) { - return this.valMap_[key].rawValue; - } - set(key, value) { - this.valMap_[key].rawValue = value; - } - value(key) { - return this.valMap_[key]; - } - } - - class DefiniteRangeConstraint$1 { - constructor(config) { - this.values = ValueMap$1.fromObject({ - max: config.max, - min: config.min, - }); - } - constrain(value) { - const max = this.values.get('max'); - const min = this.values.get('min'); - return Math.min(Math.max(value, min), max); - } - } - - class RangeConstraint$1 { - constructor(config) { - this.values = ValueMap$1.fromObject({ - max: config.max, - min: config.min, - }); - } - constrain(value) { - const max = this.values.get('max'); - const min = this.values.get('min'); - let result = value; - if (!isEmpty$1(min)) { - result = Math.max(result, min); - } - if (!isEmpty$1(max)) { - result = Math.min(result, max); - } - return result; - } - } - - class StepConstraint$1 { - constructor(step, origin = 0) { - this.step = step; - this.origin = origin; - } - constrain(value) { - const o = this.origin % this.step; - const r = Math.round((value - o) / this.step); - return o + r * this.step; - } - } - - class NumberLiteralNode$1 { - constructor(text) { - this.text = text; - } - evaluate() { - return Number(this.text); - } - toString() { - return this.text; - } - } - const BINARY_OPERATION_MAP$1 = { - '**': (v1, v2) => Math.pow(v1, v2), - '*': (v1, v2) => v1 * v2, - '/': (v1, v2) => v1 / v2, - '%': (v1, v2) => v1 % v2, - '+': (v1, v2) => v1 + v2, - '-': (v1, v2) => v1 - v2, - '<<': (v1, v2) => v1 << v2, - '>>': (v1, v2) => v1 >> v2, - '>>>': (v1, v2) => v1 >>> v2, - '&': (v1, v2) => v1 & v2, - '^': (v1, v2) => v1 ^ v2, - '|': (v1, v2) => v1 | v2, - }; - class BinaryOperationNode$1 { - constructor(operator, left, right) { - this.left = left; - this.operator = operator; - this.right = right; - } - evaluate() { - const op = BINARY_OPERATION_MAP$1[this.operator]; - if (!op) { - throw new Error(`unexpected binary operator: '${this.operator}`); - } - return op(this.left.evaluate(), this.right.evaluate()); - } - toString() { - return [ - 'b(', - this.left.toString(), - this.operator, - this.right.toString(), - ')', - ].join(' '); - } - } - const UNARY_OPERATION_MAP$1 = { - '+': (v) => v, - '-': (v) => -v, - '~': (v) => ~v, - }; - class UnaryOperationNode$1 { - constructor(operator, expr) { - this.operator = operator; - this.expression = expr; - } - evaluate() { - const op = UNARY_OPERATION_MAP$1[this.operator]; - if (!op) { - throw new Error(`unexpected unary operator: '${this.operator}`); - } - return op(this.expression.evaluate()); - } - toString() { - return ['u(', this.operator, this.expression.toString(), ')'].join(' '); - } - } - - function combineReader$1(parsers) { - return (text, cursor) => { - for (let i = 0; i < parsers.length; i++) { - const result = parsers[i](text, cursor); - if (result !== '') { - return result; - } - } - return ''; - }; - } - function readWhitespace$1(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^\s+/); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readNonZeroDigit$1(text, cursor) { - const ch = text.substr(cursor, 1); - return ch.match(/^[1-9]$/) ? ch : ''; - } - function readDecimalDigits$1(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^[0-9]+/); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readSignedInteger$1(text, cursor) { - const ds = readDecimalDigits$1(text, cursor); - if (ds !== '') { - return ds; - } - const sign = text.substr(cursor, 1); - cursor += 1; - if (sign !== '-' && sign !== '+') { - return ''; - } - const sds = readDecimalDigits$1(text, cursor); - if (sds === '') { - return ''; - } - return sign + sds; - } - function readExponentPart$1(text, cursor) { - const e = text.substr(cursor, 1); - cursor += 1; - if (e.toLowerCase() !== 'e') { - return ''; - } - const si = readSignedInteger$1(text, cursor); - if (si === '') { - return ''; - } - return e + si; - } - function readDecimalIntegerLiteral$1(text, cursor) { - const ch = text.substr(cursor, 1); - if (ch === '0') { - return ch; - } - const nzd = readNonZeroDigit$1(text, cursor); - cursor += nzd.length; - if (nzd === '') { - return ''; - } - return nzd + readDecimalDigits$1(text, cursor); - } - function readDecimalLiteral1$1(text, cursor) { - const dil = readDecimalIntegerLiteral$1(text, cursor); - cursor += dil.length; - if (dil === '') { - return ''; - } - const dot = text.substr(cursor, 1); - cursor += dot.length; - if (dot !== '.') { - return ''; - } - const dds = readDecimalDigits$1(text, cursor); - cursor += dds.length; - return dil + dot + dds + readExponentPart$1(text, cursor); - } - function readDecimalLiteral2$1(text, cursor) { - const dot = text.substr(cursor, 1); - cursor += dot.length; - if (dot !== '.') { - return ''; - } - const dds = readDecimalDigits$1(text, cursor); - cursor += dds.length; - if (dds === '') { - return ''; - } - return dot + dds + readExponentPart$1(text, cursor); - } - function readDecimalLiteral3$1(text, cursor) { - const dil = readDecimalIntegerLiteral$1(text, cursor); - cursor += dil.length; - if (dil === '') { - return ''; - } - return dil + readExponentPart$1(text, cursor); - } - const readDecimalLiteral$1 = combineReader$1([ - readDecimalLiteral1$1, - readDecimalLiteral2$1, - readDecimalLiteral3$1, - ]); - function parseBinaryDigits$1(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^[01]+/); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readBinaryIntegerLiteral$1(text, cursor) { - const prefix = text.substr(cursor, 2); - cursor += prefix.length; - if (prefix.toLowerCase() !== '0b') { - return ''; - } - const bds = parseBinaryDigits$1(text, cursor); - if (bds === '') { - return ''; - } - return prefix + bds; - } - function readOctalDigits$1(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^[0-7]+/); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readOctalIntegerLiteral$1(text, cursor) { - const prefix = text.substr(cursor, 2); - cursor += prefix.length; - if (prefix.toLowerCase() !== '0o') { - return ''; - } - const ods = readOctalDigits$1(text, cursor); - if (ods === '') { - return ''; - } - return prefix + ods; - } - function readHexDigits$1(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^[0-9a-f]+/i); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readHexIntegerLiteral$1(text, cursor) { - const prefix = text.substr(cursor, 2); - cursor += prefix.length; - if (prefix.toLowerCase() !== '0x') { - return ''; - } - const hds = readHexDigits$1(text, cursor); - if (hds === '') { - return ''; - } - return prefix + hds; - } - const readNonDecimalIntegerLiteral$1 = combineReader$1([ - readBinaryIntegerLiteral$1, - readOctalIntegerLiteral$1, - readHexIntegerLiteral$1, - ]); - const readNumericLiteral$1 = combineReader$1([ - readNonDecimalIntegerLiteral$1, - readDecimalLiteral$1, - ]); - - function parseLiteral$1(text, cursor) { - const num = readNumericLiteral$1(text, cursor); - cursor += num.length; - if (num === '') { - return null; - } - return { - evaluable: new NumberLiteralNode$1(num), - cursor: cursor, - }; - } - function parseParenthesizedExpression$1(text, cursor) { - const op = text.substr(cursor, 1); - cursor += op.length; - if (op !== '(') { - return null; - } - const expr = parseExpression$1(text, cursor); - if (!expr) { - return null; - } - cursor = expr.cursor; - cursor += readWhitespace$1(text, cursor).length; - const cl = text.substr(cursor, 1); - cursor += cl.length; - if (cl !== ')') { - return null; - } - return { - evaluable: expr.evaluable, - cursor: cursor, - }; - } - function parsePrimaryExpression$1(text, cursor) { - var _a; - return ((_a = parseLiteral$1(text, cursor)) !== null && _a !== void 0 ? _a : parseParenthesizedExpression$1(text, cursor)); - } - function parseUnaryExpression$1(text, cursor) { - const expr = parsePrimaryExpression$1(text, cursor); - if (expr) { - return expr; - } - const op = text.substr(cursor, 1); - cursor += op.length; - if (op !== '+' && op !== '-' && op !== '~') { - return null; - } - const num = parseUnaryExpression$1(text, cursor); - if (!num) { - return null; - } - cursor = num.cursor; - return { - cursor: cursor, - evaluable: new UnaryOperationNode$1(op, num.evaluable), - }; - } - function readBinaryOperator$1(ops, text, cursor) { - cursor += readWhitespace$1(text, cursor).length; - const op = ops.filter((op) => text.startsWith(op, cursor))[0]; - if (!op) { - return null; - } - cursor += op.length; - cursor += readWhitespace$1(text, cursor).length; - return { - cursor: cursor, - operator: op, - }; - } - function createBinaryOperationExpressionParser$1(exprParser, ops) { - return (text, cursor) => { - const firstExpr = exprParser(text, cursor); - if (!firstExpr) { - return null; - } - cursor = firstExpr.cursor; - let expr = firstExpr.evaluable; - for (;;) { - const op = readBinaryOperator$1(ops, text, cursor); - if (!op) { - break; - } - cursor = op.cursor; - const nextExpr = exprParser(text, cursor); - if (!nextExpr) { - return null; - } - cursor = nextExpr.cursor; - expr = new BinaryOperationNode$1(op.operator, expr, nextExpr.evaluable); - } - return expr - ? { - cursor: cursor, - evaluable: expr, - } - : null; - }; - } - const parseBinaryOperationExpression$1 = [ - ['**'], - ['*', '/', '%'], - ['+', '-'], - ['<<', '>>>', '>>'], - ['&'], - ['^'], - ['|'], - ].reduce((parser, ops) => { - return createBinaryOperationExpressionParser$1(parser, ops); - }, parseUnaryExpression$1); - function parseExpression$1(text, cursor) { - cursor += readWhitespace$1(text, cursor).length; - return parseBinaryOperationExpression$1(text, cursor); - } - function parseEcmaNumberExpression$1(text) { - const expr = parseExpression$1(text, 0); - if (!expr) { - return null; - } - const cursor = expr.cursor + readWhitespace$1(text, expr.cursor).length; - if (cursor !== text.length) { - return null; - } - return expr.evaluable; - } - - function parseNumber$1(text) { - var _a; - const r = parseEcmaNumberExpression$1(text); - return (_a = r === null || r === void 0 ? void 0 : r.evaluate()) !== null && _a !== void 0 ? _a : null; - } - function numberFromUnknown$1(value) { - if (typeof value === 'number') { - return value; - } - if (typeof value === 'string') { - const pv = parseNumber$1(value); - if (!isEmpty$1(pv)) { - return pv; - } - } - return 0; - } - function numberToString(value) { - return String(value); - } - function createNumberFormatter$1(digits) { - return (value) => { - return value.toFixed(Math.max(Math.min(digits, 20), 0)); - }; - } - - function mapRange$1(value, start1, end1, start2, end2) { - const p = (value - start1) / (end1 - start1); - return start2 + p * (end2 - start2); - } - function getDecimalDigits$1(value) { - const text = String(value.toFixed(10)); - const frac = text.split('.')[1]; - return frac.replace(/0+$/, '').length; - } - function constrainRange$1(value, min, max) { - return Math.min(Math.max(value, min), max); - } - function loopRange$1(value, max) { - return ((value % max) + max) % max; - } - function getSuitableDecimalDigits$1(params, rawValue) { - return !isEmpty$1(params.step) - ? getDecimalDigits$1(params.step) - : Math.max(getDecimalDigits$1(rawValue), 2); - } - function getSuitableKeyScale$1(params) { - var _a; - return (_a = params.step) !== null && _a !== void 0 ? _a : 1; - } - function getSuitablePointerScale$1(params, rawValue) { - var _a; - const base = Math.abs((_a = params.step) !== null && _a !== void 0 ? _a : rawValue); - return base === 0 ? 0.1 : Math.pow(10, Math.floor(Math.log10(base)) - 1); - } - function createStepConstraint$1(params, initialValue) { - if (!isEmpty$1(params.step)) { - return new StepConstraint$1(params.step, initialValue); - } - return null; - } - function createRangeConstraint$1(params) { - if (!isEmpty$1(params.max) && !isEmpty$1(params.min)) { - return new DefiniteRangeConstraint$1({ - max: params.max, - min: params.min, - }); - } - if (!isEmpty$1(params.max) || !isEmpty$1(params.min)) { - return new RangeConstraint$1({ - max: params.max, - min: params.min, - }); - } - return null; - } - function createNumberTextPropsObject$1(params, initialValue) { - var _a, _b, _c; - return { - formatter: (_a = params.format) !== null && _a !== void 0 ? _a : createNumberFormatter$1(getSuitableDecimalDigits$1(params, initialValue)), - keyScale: (_b = params.keyScale) !== null && _b !== void 0 ? _b : getSuitableKeyScale$1(params), - pointerScale: (_c = params.pointerScale) !== null && _c !== void 0 ? _c : getSuitablePointerScale$1(params, initialValue), - }; - } - function createNumberTextInputParamsParser$1(p) { - return { - format: p.optional.function, - keyScale: p.optional.number, - max: p.optional.number, - min: p.optional.number, - pointerScale: p.optional.number, - step: p.optional.number, - }; - } - - function createPointAxis$1(config) { - return { - constraint: config.constraint, - textProps: ValueMap$1.fromObject(createNumberTextPropsObject$1(config.params, config.initialValue)), - }; - } - - class BladeApi$1 { - constructor(controller) { - this.controller = controller; - } - get element() { - return this.controller.view.element; - } - get disabled() { - return this.controller.viewProps.get('disabled'); - } - set disabled(disabled) { - this.controller.viewProps.set('disabled', disabled); - } - get hidden() { - return this.controller.viewProps.get('hidden'); - } - set hidden(hidden) { - this.controller.viewProps.set('hidden', hidden); - } - dispose() { - this.controller.viewProps.set('disposed', true); - } - importState(state) { - return this.controller.importState(state); - } - exportState() { - return this.controller.exportState(); - } - } - - class TpEvent$1 { - constructor(target) { - this.target = target; - } - } - class TpChangeEvent$1 extends TpEvent$1 { - constructor(target, value, last) { - super(target); - this.value = value; - this.last = last !== null && last !== void 0 ? last : true; - } - } - class TpFoldEvent$1 extends TpEvent$1 { - constructor(target, expanded) { - super(target); - this.expanded = expanded; - } - } - class TpTabSelectEvent$1 extends TpEvent$1 { - constructor(target, index) { - super(target); - this.index = index; - } - } - class TpMouseEvent extends TpEvent$1 { - constructor(target, nativeEvent) { - super(target); - this.native = nativeEvent; - } - } - - class BindingApi$1 extends BladeApi$1 { - constructor(controller) { - super(controller); - this.onValueChange_ = this.onValueChange_.bind(this); - this.emitter_ = new Emitter$1(); - this.controller.value.emitter.on('change', this.onValueChange_); - } - get label() { - return this.controller.labelController.props.get('label'); - } - set label(label) { - this.controller.labelController.props.set('label', label); - } - get key() { - return this.controller.value.binding.target.key; - } - get tag() { - return this.controller.tag; - } - set tag(tag) { - this.controller.tag = tag; - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }, { - key: handler, - }); - return this; - } - off(eventName, handler) { - this.emitter_.off(eventName, handler); - return this; - } - refresh() { - this.controller.value.fetch(); - } - onValueChange_(ev) { - const value = this.controller.value; - this.emitter_.emit('change', new TpChangeEvent$1(this, forceCast$1(value.binding.target.read()), ev.options.last)); - } - } - - class InputBindingValue { - constructor(value, binding) { - this.onValueBeforeChange_ = this.onValueBeforeChange_.bind(this); - this.onValueChange_ = this.onValueChange_.bind(this); - this.binding = binding; - this.value_ = value; - this.value_.emitter.on('beforechange', this.onValueBeforeChange_); - this.value_.emitter.on('change', this.onValueChange_); - this.emitter = new Emitter$1(); - } - get rawValue() { - return this.value_.rawValue; - } - set rawValue(rawValue) { - this.value_.rawValue = rawValue; - } - setRawValue(rawValue, options) { - this.value_.setRawValue(rawValue, options); - } - fetch() { - this.value_.rawValue = this.binding.read(); - } - push() { - this.binding.write(this.value_.rawValue); - } - onValueBeforeChange_(ev) { - this.emitter.emit('beforechange', Object.assign(Object.assign({}, ev), { sender: this })); - } - onValueChange_(ev) { - this.push(); - this.emitter.emit('change', Object.assign(Object.assign({}, ev), { sender: this })); - } - } - function isInputBindingValue(v) { - if (!('binding' in v)) { - return false; - } - const b = v['binding']; - return isBinding$1(b) && 'read' in b && 'write' in b; - } - - function parseObject$1(value, keyToParserMap) { - const keys = Object.keys(keyToParserMap); - const result = keys.reduce((tmp, key) => { - if (tmp === undefined) { - return undefined; - } - const parser = keyToParserMap[key]; - const result = parser(value[key]); - return result.succeeded - ? Object.assign(Object.assign({}, tmp), { [key]: result.value }) : undefined; - }, {}); - return forceCast$1(result); - } - function parseArray$1(value, parseItem) { - return value.reduce((tmp, item) => { - if (tmp === undefined) { - return undefined; - } - const result = parseItem(item); - if (!result.succeeded || result.value === undefined) { - return undefined; - } - return [...tmp, result.value]; - }, []); - } - function isObject$2(value) { - if (value === null) { - return false; - } - return typeof value === 'object'; - } - function createMicroParserBuilder$1(parse) { - return (optional) => (v) => { - if (!optional && v === undefined) { - return { - succeeded: false, - value: undefined, - }; - } - if (optional && v === undefined) { - return { - succeeded: true, - value: undefined, - }; - } - const result = parse(v); - return result !== undefined - ? { - succeeded: true, - value: result, - } - : { - succeeded: false, - value: undefined, - }; - }; - } - function createMicroParserBuilders$1(optional) { - return { - custom: (parse) => createMicroParserBuilder$1(parse)(optional), - boolean: createMicroParserBuilder$1((v) => typeof v === 'boolean' ? v : undefined)(optional), - number: createMicroParserBuilder$1((v) => typeof v === 'number' ? v : undefined)(optional), - string: createMicroParserBuilder$1((v) => typeof v === 'string' ? v : undefined)(optional), - function: createMicroParserBuilder$1((v) => - typeof v === 'function' ? v : undefined)(optional), - constant: (value) => createMicroParserBuilder$1((v) => (v === value ? value : undefined))(optional), - raw: createMicroParserBuilder$1((v) => v)(optional), - object: (keyToParserMap) => createMicroParserBuilder$1((v) => { - if (!isObject$2(v)) { - return undefined; - } - return parseObject$1(v, keyToParserMap); - })(optional), - array: (itemParser) => createMicroParserBuilder$1((v) => { - if (!Array.isArray(v)) { - return undefined; - } - return parseArray$1(v, itemParser); - })(optional), - }; - } - const MicroParsers$1 = { - optional: createMicroParserBuilders$1(true), - required: createMicroParserBuilders$1(false), - }; - function parseRecord$1(value, keyToParserMap) { - const map = keyToParserMap(MicroParsers$1); - const result = MicroParsers$1.required.object(map)(value); - return result.succeeded ? result.value : undefined; - } - - function importBladeState$1(state, superImport, parser, callback) { - if (superImport && !superImport(state)) { - return false; - } - const result = parseRecord$1(state, parser); - return result ? callback(result) : false; - } - function exportBladeState$1(superExport, thisState) { - var _a; - return deepMerge$1((_a = superExport === null || superExport === void 0 ? void 0 : superExport()) !== null && _a !== void 0 ? _a : {}, thisState); - } - - function isValueBladeController$1(bc) { - return 'value' in bc; - } - - function isBindingValue$1(v) { - if (!isObject$1$1(v) || !('binding' in v)) { - return false; - } - const b = v.binding; - return isBinding$1(b); - } - - const SVG_NS$1 = 'http://www.w3.org/2000/svg'; - function forceReflow$1(element) { - element.offsetHeight; - } - function disableTransitionTemporarily$1(element, callback) { - const t = element.style.transition; - element.style.transition = 'none'; - callback(); - element.style.transition = t; - } - function supportsTouch$1(doc) { - return doc.ontouchstart !== undefined; - } - function getGlobalObject() { - return globalThis; - } - function getWindowDocument() { - const globalObj = forceCast$1(getGlobalObject()); - return globalObj.document; - } - function getCanvasContext$1(canvasElement) { - const win = canvasElement.ownerDocument.defaultView; - if (!win) { - return null; - } - const isBrowser = 'document' in win; - return isBrowser - ? canvasElement.getContext('2d', { - willReadFrequently: true, - }) - : null; - } - const ICON_ID_TO_INNER_HTML_MAP$1 = { - check: '', - dropdown: '', - p2dpad: '', - }; - function createSvgIconElement$1(document, iconId) { - const elem = document.createElementNS(SVG_NS$1, 'svg'); - elem.innerHTML = ICON_ID_TO_INNER_HTML_MAP$1[iconId]; - return elem; - } - function insertElementAt$1(parentElement, element, index) { - parentElement.insertBefore(element, parentElement.children[index]); - } - function removeElement$1(element) { - if (element.parentElement) { - element.parentElement.removeChild(element); - } - } - function removeChildElements$1(element) { - while (element.children.length > 0) { - element.removeChild(element.children[0]); - } - } - function removeChildNodes$1(element) { - while (element.childNodes.length > 0) { - element.removeChild(element.childNodes[0]); - } - } - function findNextTarget$1(ev) { - if (ev.relatedTarget) { - return forceCast$1(ev.relatedTarget); - } - if ('explicitOriginalTarget' in ev) { - return ev.explicitOriginalTarget; - } - return null; - } - - function bindValue$1(value, applyValue) { - value.emitter.on('change', (ev) => { - applyValue(ev.rawValue); - }); - applyValue(value.rawValue); - } - function bindValueMap$1(valueMap, key, applyValue) { - bindValue$1(valueMap.value(key), applyValue); - } - - const PREFIX$1 = 'tp'; - function ClassName$1(viewName) { - const fn = (opt_elementName, opt_modifier) => { - return [ - PREFIX$1, - '-', - viewName, - 'v', - opt_elementName ? `_${opt_elementName}` : '', - opt_modifier ? `-${opt_modifier}` : '', - ].join(''); - }; - return fn; - } - - const cn$r = ClassName$1('lbl'); - function createLabelNode$1(doc, label) { - const frag = doc.createDocumentFragment(); - const lineNodes = label.split('\n').map((line) => { - return doc.createTextNode(line); - }); - lineNodes.forEach((lineNode, index) => { - if (index > 0) { - frag.appendChild(doc.createElement('br')); - } - frag.appendChild(lineNode); - }); - return frag; - } - class LabelView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$r()); - config.viewProps.bindClassModifiers(this.element); - const labelElem = doc.createElement('div'); - labelElem.classList.add(cn$r('l')); - bindValueMap$1(config.props, 'label', (value) => { - if (isEmpty$1(value)) { - this.element.classList.add(cn$r(undefined, 'nol')); - } - else { - this.element.classList.remove(cn$r(undefined, 'nol')); - removeChildNodes$1(labelElem); - labelElem.appendChild(createLabelNode$1(doc, value)); - } - }); - this.element.appendChild(labelElem); - this.labelElement = labelElem; - const valueElem = doc.createElement('div'); - valueElem.classList.add(cn$r('v')); - this.element.appendChild(valueElem); - this.valueElement = valueElem; - } - } - - class LabelController$1 { - constructor(doc, config) { - this.props = config.props; - this.valueController = config.valueController; - this.viewProps = config.valueController.viewProps; - this.view = new LabelView$1(doc, { - props: config.props, - viewProps: this.viewProps, - }); - this.view.valueElement.appendChild(this.valueController.view.element); - } - importProps(state) { - return importBladeState$1(state, null, (p) => ({ - label: p.optional.string, - }), (result) => { - this.props.set('label', result.label); - return true; - }); - } - exportProps() { - return exportBladeState$1(null, { - label: this.props.get('label'), - }); - } - } - - function getAllBladePositions$1() { - return ['veryfirst', 'first', 'last', 'verylast']; - } - - const cn$q$1 = ClassName$1(''); - const POS_TO_CLASS_NAME_MAP$1 = { - veryfirst: 'vfst', - first: 'fst', - last: 'lst', - verylast: 'vlst', - }; - class BladeController$1 { - constructor(config) { - this.parent_ = null; - this.blade = config.blade; - this.view = config.view; - this.viewProps = config.viewProps; - const elem = this.view.element; - this.blade.value('positions').emitter.on('change', () => { - getAllBladePositions$1().forEach((pos) => { - elem.classList.remove(cn$q$1(undefined, POS_TO_CLASS_NAME_MAP$1[pos])); - }); - this.blade.get('positions').forEach((pos) => { - elem.classList.add(cn$q$1(undefined, POS_TO_CLASS_NAME_MAP$1[pos])); - }); - }); - this.viewProps.handleDispose(() => { - removeElement$1(elem); - }); - } - get parent() { - return this.parent_; - } - set parent(parent) { - this.parent_ = parent; - this.viewProps.set('parent', this.parent_ ? this.parent_.viewProps : null); - } - importState(state) { - return importBladeState$1(state, null, (p) => ({ - disabled: p.required.boolean, - hidden: p.required.boolean, - }), (result) => { - this.viewProps.importState(result); - return true; - }); - } - exportState() { - return exportBladeState$1(null, Object.assign({}, this.viewProps.exportState())); - } - } - - class LabeledValueBladeController$1 extends BladeController$1 { - constructor(doc, config) { - if (config.value !== config.valueController.value) { - throw TpError$1.shouldNeverHappen(); - } - const viewProps = config.valueController.viewProps; - const lc = new LabelController$1(doc, { - blade: config.blade, - props: config.props, - valueController: config.valueController, - }); - super(Object.assign(Object.assign({}, config), { view: new LabelView$1(doc, { - props: config.props, - viewProps: viewProps, - }), viewProps: viewProps })); - this.labelController = lc; - this.value = config.value; - this.valueController = config.valueController; - this.view.valueElement.appendChild(this.valueController.view.element); - } - importState(state) { - return importBladeState$1(state, (s) => { - var _a, _b, _c; - return super.importState(s) && - this.labelController.importProps(s) && - ((_c = (_b = (_a = this.valueController).importProps) === null || _b === void 0 ? void 0 : _b.call(_a, state)) !== null && _c !== void 0 ? _c : true); - }, (p) => ({ - value: p.optional.raw, - }), (result) => { - if (result.value) { - this.value.rawValue = result.value; - } - return true; - }); - } - exportState() { - var _a, _b, _c; - return exportBladeState$1(() => super.exportState(), Object.assign(Object.assign({ value: this.value.rawValue }, this.labelController.exportProps()), ((_c = (_b = (_a = this.valueController).exportProps) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : {}))); - } - } - - function excludeValue(state) { - const result = Object.assign({}, state); - delete result.value; - return result; - } - class BindingController extends LabeledValueBladeController$1 { - constructor(doc, config) { - super(doc, config); - this.tag = config.tag; - } - importState(state) { - return importBladeState$1(state, - (_s) => super.importState(excludeValue(state)), (p) => ({ - tag: p.optional.string, - }), (result) => { - this.tag = result.tag; - return true; - }); - } - exportState() { - return exportBladeState$1(() => excludeValue(super.exportState()), { - binding: { - key: this.value.binding.target.key, - value: this.value.binding.target.read(), - }, - tag: this.tag, - }); - } - } - function isBindingController(bc) { - return isValueBladeController$1(bc) && isBindingValue$1(bc.value); - } - - class InputBindingController extends BindingController { - importState(state) { - return importBladeState$1(state, (s) => super.importState(s), (p) => ({ - binding: p.required.object({ - value: p.required.raw, - }), - }), (result) => { - this.value.binding.inject(result.binding.value); - this.value.fetch(); - return true; - }); - } - } - function isInputBindingController(bc) { - return isValueBladeController$1(bc) && isInputBindingValue(bc.value); - } - - function fillBuffer$1(buffer, bufferSize) { - while (buffer.length < bufferSize) { - buffer.push(undefined); - } - } - function initializeBuffer$1(bufferSize) { - const buffer = []; - fillBuffer$1(buffer, bufferSize); - return buffer; - } - function createTrimmedBuffer$1(buffer) { - const index = buffer.indexOf(undefined); - return forceCast$1(index < 0 ? buffer : buffer.slice(0, index)); - } - function createPushedBuffer$1(buffer, newValue) { - const newBuffer = [...createTrimmedBuffer$1(buffer), newValue]; - if (newBuffer.length > buffer.length) { - newBuffer.splice(0, newBuffer.length - buffer.length); - } - else { - fillBuffer$1(newBuffer, buffer.length); - } - return newBuffer; - } - - class MonitorBindingValue { - constructor(config) { - this.emitter = new Emitter$1(); - this.onTick_ = this.onTick_.bind(this); - this.onValueBeforeChange_ = this.onValueBeforeChange_.bind(this); - this.onValueChange_ = this.onValueChange_.bind(this); - this.binding = config.binding; - this.value_ = createValue$1(initializeBuffer$1(config.bufferSize)); - this.value_.emitter.on('beforechange', this.onValueBeforeChange_); - this.value_.emitter.on('change', this.onValueChange_); - this.ticker = config.ticker; - this.ticker.emitter.on('tick', this.onTick_); - this.fetch(); - } - get rawValue() { - return this.value_.rawValue; - } - set rawValue(rawValue) { - this.value_.rawValue = rawValue; - } - setRawValue(rawValue, options) { - this.value_.setRawValue(rawValue, options); - } - fetch() { - this.value_.rawValue = createPushedBuffer$1(this.value_.rawValue, this.binding.read()); - } - onTick_() { - this.fetch(); - } - onValueBeforeChange_(ev) { - this.emitter.emit('beforechange', Object.assign(Object.assign({}, ev), { sender: this })); - } - onValueChange_(ev) { - this.emitter.emit('change', Object.assign(Object.assign({}, ev), { sender: this })); - } - } - function isMonitorBindingValue(v) { - if (!('binding' in v)) { - return false; - } - const b = v['binding']; - return isBinding$1(b) && 'read' in b && !('write' in b); - } - - class MonitorBindingController extends BindingController { - exportState() { - return exportBladeState$1(() => super.exportState(), { - binding: { - readonly: true, - }, - }); - } - } - function isMonitorBindingController(bc) { - return (isValueBladeController$1(bc) && - isMonitorBindingValue(bc.value)); - } - - class ButtonApi$1 extends BladeApi$1 { - get label() { - return this.controller.labelController.props.get('label'); - } - set label(label) { - this.controller.labelController.props.set('label', label); - } - get title() { - var _a; - return (_a = this.controller.buttonController.props.get('title')) !== null && _a !== void 0 ? _a : ''; - } - set title(title) { - this.controller.buttonController.props.set('title', title); - } - on(eventName, handler) { - const bh = handler.bind(this); - const emitter = this.controller.buttonController.emitter; - emitter.on(eventName, (ev) => { - bh(new TpMouseEvent(this, ev.nativeEvent)); - }); - return this; - } - off(eventName, handler) { - const emitter = this.controller.buttonController.emitter; - emitter.off(eventName, handler); - return this; - } - } - - function applyClass$1(elem, className, active) { - if (active) { - elem.classList.add(className); - } - else { - elem.classList.remove(className); - } - } - function valueToClassName$1(elem, className) { - return (value) => { - applyClass$1(elem, className, value); - }; - } - function bindValueToTextContent$1(value, elem) { - bindValue$1(value, (text) => { - elem.textContent = text !== null && text !== void 0 ? text : ''; - }); - } - - const cn$p$1 = ClassName$1('btn'); - class ButtonView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$p$1()); - config.viewProps.bindClassModifiers(this.element); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(cn$p$1('b')); - config.viewProps.bindDisabled(buttonElem); - this.element.appendChild(buttonElem); - this.buttonElement = buttonElem; - const titleElem = doc.createElement('div'); - titleElem.classList.add(cn$p$1('t')); - bindValueToTextContent$1(config.props.value('title'), titleElem); - this.buttonElement.appendChild(titleElem); - } - } - - class ButtonController$1 { - constructor(doc, config) { - this.emitter = new Emitter$1(); - this.onClick_ = this.onClick_.bind(this); - this.props = config.props; - this.viewProps = config.viewProps; - this.view = new ButtonView$1(doc, { - props: this.props, - viewProps: this.viewProps, - }); - this.view.buttonElement.addEventListener('click', this.onClick_); - } - importProps(state) { - return importBladeState$1(state, null, (p) => ({ - title: p.optional.string, - }), (result) => { - this.props.set('title', result.title); - return true; - }); - } - exportProps() { - return exportBladeState$1(null, { - title: this.props.get('title'), - }); - } - onClick_(ev) { - this.emitter.emit('click', { - nativeEvent: ev, - sender: this, - }); - } - } - - class ButtonBladeController$1 extends BladeController$1 { - constructor(doc, config) { - const bc = new ButtonController$1(doc, { - props: config.buttonProps, - viewProps: config.viewProps, - }); - const lc = new LabelController$1(doc, { - blade: config.blade, - props: config.labelProps, - valueController: bc, - }); - super({ - blade: config.blade, - view: lc.view, - viewProps: config.viewProps, - }); - this.buttonController = bc; - this.labelController = lc; - } - importState(state) { - return importBladeState$1(state, (s) => super.importState(s) && - this.buttonController.importProps(s) && - this.labelController.importProps(s), () => ({}), () => true); - } - exportState() { - return exportBladeState$1(() => super.exportState(), Object.assign(Object.assign({}, this.buttonController.exportProps()), this.labelController.exportProps())); - } - } - - class Semver$1 { - constructor(text) { - const [core, prerelease] = text.split('-'); - const coreComps = core.split('.'); - this.major = parseInt(coreComps[0], 10); - this.minor = parseInt(coreComps[1], 10); - this.patch = parseInt(coreComps[2], 10); - this.prerelease = prerelease !== null && prerelease !== void 0 ? prerelease : null; - } - toString() { - const core = [this.major, this.minor, this.patch].join('.'); - return this.prerelease !== null ? [core, this.prerelease].join('-') : core; - } - } - - const VERSION$1 = new Semver$1('2.0.4'); - - function createPlugin$1(plugin) { - return Object.assign({ core: VERSION$1 }, plugin); - } - - const ButtonBladePlugin = createPlugin$1({ - id: 'button', - type: 'blade', - accept(params) { - const result = parseRecord$1(params, (p) => ({ - title: p.required.string, - view: p.required.constant('button'), - label: p.optional.string, - })); - return result ? { params: result } : null; - }, - controller(args) { - return new ButtonBladeController$1(args.document, { - blade: args.blade, - buttonProps: ValueMap$1.fromObject({ - title: args.params.title, - }), - labelProps: ValueMap$1.fromObject({ - label: args.params.label, - }), - viewProps: args.viewProps, - }); - }, - api(args) { - if (args.controller instanceof ButtonBladeController$1) { - return new ButtonApi$1(args.controller); - } - return null; - }, - }); - - function addButtonAsBlade$1(api, params) { - return api.addBlade(Object.assign(Object.assign({}, params), { view: 'button' })); - } - function addFolderAsBlade$1(api, params) { - return api.addBlade(Object.assign(Object.assign({}, params), { view: 'folder' })); - } - function addTabAsBlade$1(api, params) { - return api.addBlade(Object.assign(Object.assign({}, params), { view: 'tab' })); - } - - function isRefreshable$1(value) { - if (!isObject$1$1(value)) { - return false; - } - return 'refresh' in value && typeof value.refresh === 'function'; - } - - function createBindingTarget$1(obj, key) { - if (!BindingTarget$1.isBindable(obj)) { - throw TpError$1.notBindable(); - } - return new BindingTarget$1(obj, key); - } - class RackApi$1 { - constructor(controller, pool) { - this.onRackValueChange_ = this.onRackValueChange_.bind(this); - this.controller_ = controller; - this.emitter_ = new Emitter$1(); - this.pool_ = pool; - const rack = this.controller_.rack; - rack.emitter.on('valuechange', this.onRackValueChange_); - } - get children() { - return this.controller_.rack.children.map((bc) => this.pool_.createApi(bc)); - } - addBinding(object, key, opt_params) { - const params = opt_params !== null && opt_params !== void 0 ? opt_params : {}; - const doc = this.controller_.element.ownerDocument; - const bc = this.pool_.createBinding(doc, createBindingTarget$1(object, key), params); - const api = this.pool_.createBindingApi(bc); - return this.add(api, params.index); - } - addFolder(params) { - return addFolderAsBlade$1(this, params); - } - addButton(params) { - return addButtonAsBlade$1(this, params); - } - addTab(params) { - return addTabAsBlade$1(this, params); - } - add(api, opt_index) { - const bc = api.controller; - this.controller_.rack.add(bc, opt_index); - return api; - } - remove(api) { - this.controller_.rack.remove(api.controller); - } - addBlade(params) { - const doc = this.controller_.element.ownerDocument; - const bc = this.pool_.createBlade(doc, params); - const api = this.pool_.createApi(bc); - return this.add(api, params.index); - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }, { - key: handler, - }); - return this; - } - off(eventName, handler) { - this.emitter_.off(eventName, handler); - return this; - } - refresh() { - this.children.forEach((c) => { - if (isRefreshable$1(c)) { - c.refresh(); - } - }); - } - onRackValueChange_(ev) { - const bc = ev.bladeController; - const api = this.pool_.createApi(bc); - const binding = isBindingValue$1(bc.value) ? bc.value.binding : null; - this.emitter_.emit('change', new TpChangeEvent$1(api, binding ? binding.target.read() : bc.value.rawValue, ev.options.last)); - } - } - - class ContainerBladeApi$1 extends BladeApi$1 { - constructor(controller, pool) { - super(controller); - this.rackApi_ = new RackApi$1(controller.rackController, pool); - } - refresh() { - this.rackApi_.refresh(); - } - } - - class ContainerBladeController$1 extends BladeController$1 { - constructor(config) { - super({ - blade: config.blade, - view: config.view, - viewProps: config.rackController.viewProps, - }); - this.rackController = config.rackController; - } - importState(state) { - return importBladeState$1(state, (s) => super.importState(s), (p) => ({ - children: p.required.array(p.required.raw), - }), (result) => { - return this.rackController.rack.children.every((c, index) => { - return c.importState(result.children[index]); - }); - }); - } - exportState() { - return exportBladeState$1(() => super.exportState(), { - children: this.rackController.rack.children.map((c) => c.exportState()), - }); - } - } - function isContainerBladeController$1(bc) { - return 'rackController' in bc; - } - - class NestedOrderedSet$1 { - constructor(extract) { - this.emitter = new Emitter$1(); - this.items_ = []; - this.cache_ = new Set(); - this.onSubListAdd_ = this.onSubListAdd_.bind(this); - this.onSubListRemove_ = this.onSubListRemove_.bind(this); - this.extract_ = extract; - } - get items() { - return this.items_; - } - allItems() { - return Array.from(this.cache_); - } - find(callback) { - for (const item of this.allItems()) { - if (callback(item)) { - return item; - } - } - return null; - } - includes(item) { - return this.cache_.has(item); - } - add(item, opt_index) { - if (this.includes(item)) { - throw TpError$1.shouldNeverHappen(); - } - const index = opt_index !== undefined ? opt_index : this.items_.length; - this.items_.splice(index, 0, item); - this.cache_.add(item); - const subList = this.extract_(item); - if (subList) { - subList.emitter.on('add', this.onSubListAdd_); - subList.emitter.on('remove', this.onSubListRemove_); - subList.allItems().forEach((i) => { - this.cache_.add(i); - }); - } - this.emitter.emit('add', { - index: index, - item: item, - root: this, - target: this, - }); - } - remove(item) { - const index = this.items_.indexOf(item); - if (index < 0) { - return; - } - this.items_.splice(index, 1); - this.cache_.delete(item); - const subList = this.extract_(item); - if (subList) { - subList.allItems().forEach((i) => { - this.cache_.delete(i); - }); - subList.emitter.off('add', this.onSubListAdd_); - subList.emitter.off('remove', this.onSubListRemove_); - } - this.emitter.emit('remove', { - index: index, - item: item, - root: this, - target: this, - }); - } - onSubListAdd_(ev) { - this.cache_.add(ev.item); - this.emitter.emit('add', { - index: ev.index, - item: ev.item, - root: this, - target: ev.target, - }); - } - onSubListRemove_(ev) { - this.cache_.delete(ev.item); - this.emitter.emit('remove', { - index: ev.index, - item: ev.item, - root: this, - target: ev.target, - }); - } - } - - function findValueBladeController$1(bcs, v) { - for (let i = 0; i < bcs.length; i++) { - const bc = bcs[i]; - if (isValueBladeController$1(bc) && bc.value === v) { - return bc; - } - } - return null; - } - function findSubBladeControllerSet$1(bc) { - return isContainerBladeController$1(bc) - ? bc.rackController.rack['bcSet_'] - : null; - } - class Rack$1 { - constructor(config) { - var _a, _b; - this.emitter = new Emitter$1(); - this.onBladePositionsChange_ = this.onBladePositionsChange_.bind(this); - this.onSetAdd_ = this.onSetAdd_.bind(this); - this.onSetRemove_ = this.onSetRemove_.bind(this); - this.onChildDispose_ = this.onChildDispose_.bind(this); - this.onChildPositionsChange_ = this.onChildPositionsChange_.bind(this); - this.onChildValueChange_ = this.onChildValueChange_.bind(this); - this.onChildViewPropsChange_ = this.onChildViewPropsChange_.bind(this); - this.onRackLayout_ = this.onRackLayout_.bind(this); - this.onRackValueChange_ = this.onRackValueChange_.bind(this); - this.blade_ = (_a = config.blade) !== null && _a !== void 0 ? _a : null; - (_b = this.blade_) === null || _b === void 0 ? void 0 : _b.value('positions').emitter.on('change', this.onBladePositionsChange_); - this.viewProps = config.viewProps; - this.bcSet_ = new NestedOrderedSet$1(findSubBladeControllerSet$1); - this.bcSet_.emitter.on('add', this.onSetAdd_); - this.bcSet_.emitter.on('remove', this.onSetRemove_); - } - get children() { - return this.bcSet_.items; - } - add(bc, opt_index) { - var _a; - (_a = bc.parent) === null || _a === void 0 ? void 0 : _a.remove(bc); - bc.parent = this; - this.bcSet_.add(bc, opt_index); - } - remove(bc) { - bc.parent = null; - this.bcSet_.remove(bc); - } - find(finder) { - return this.bcSet_.allItems().filter(finder); - } - onSetAdd_(ev) { - this.updatePositions_(); - const root = ev.target === ev.root; - this.emitter.emit('add', { - bladeController: ev.item, - index: ev.index, - root: root, - sender: this, - }); - if (!root) { - return; - } - const bc = ev.item; - bc.viewProps.emitter.on('change', this.onChildViewPropsChange_); - bc.blade - .value('positions') - .emitter.on('change', this.onChildPositionsChange_); - bc.viewProps.handleDispose(this.onChildDispose_); - if (isValueBladeController$1(bc)) { - bc.value.emitter.on('change', this.onChildValueChange_); - } - else if (isContainerBladeController$1(bc)) { - const rack = bc.rackController.rack; - if (rack) { - const emitter = rack.emitter; - emitter.on('layout', this.onRackLayout_); - emitter.on('valuechange', this.onRackValueChange_); - } - } - } - onSetRemove_(ev) { - this.updatePositions_(); - const root = ev.target === ev.root; - this.emitter.emit('remove', { - bladeController: ev.item, - root: root, - sender: this, - }); - if (!root) { - return; - } - const bc = ev.item; - if (isValueBladeController$1(bc)) { - bc.value.emitter.off('change', this.onChildValueChange_); - } - else if (isContainerBladeController$1(bc)) { - const rack = bc.rackController.rack; - if (rack) { - const emitter = rack.emitter; - emitter.off('layout', this.onRackLayout_); - emitter.off('valuechange', this.onRackValueChange_); - } - } - } - updatePositions_() { - const visibleItems = this.bcSet_.items.filter((bc) => !bc.viewProps.get('hidden')); - const firstVisibleItem = visibleItems[0]; - const lastVisibleItem = visibleItems[visibleItems.length - 1]; - this.bcSet_.items.forEach((bc) => { - const ps = []; - if (bc === firstVisibleItem) { - ps.push('first'); - if (!this.blade_ || - this.blade_.get('positions').includes('veryfirst')) { - ps.push('veryfirst'); - } - } - if (bc === lastVisibleItem) { - ps.push('last'); - if (!this.blade_ || this.blade_.get('positions').includes('verylast')) { - ps.push('verylast'); - } - } - bc.blade.set('positions', ps); - }); - } - onChildPositionsChange_() { - this.updatePositions_(); - this.emitter.emit('layout', { - sender: this, - }); - } - onChildViewPropsChange_(_ev) { - this.updatePositions_(); - this.emitter.emit('layout', { - sender: this, - }); - } - onChildDispose_() { - const disposedUcs = this.bcSet_.items.filter((bc) => { - return bc.viewProps.get('disposed'); - }); - disposedUcs.forEach((bc) => { - this.bcSet_.remove(bc); - }); - } - onChildValueChange_(ev) { - const bc = findValueBladeController$1(this.find(isValueBladeController$1), ev.sender); - if (!bc) { - throw TpError$1.alreadyDisposed(); - } - this.emitter.emit('valuechange', { - bladeController: bc, - options: ev.options, - sender: this, - }); - } - onRackLayout_(_) { - this.updatePositions_(); - this.emitter.emit('layout', { - sender: this, - }); - } - onRackValueChange_(ev) { - this.emitter.emit('valuechange', { - bladeController: ev.bladeController, - options: ev.options, - sender: this, - }); - } - onBladePositionsChange_() { - this.updatePositions_(); - } - } - - class RackController$1 { - constructor(config) { - this.onRackAdd_ = this.onRackAdd_.bind(this); - this.onRackRemove_ = this.onRackRemove_.bind(this); - this.element = config.element; - this.viewProps = config.viewProps; - const rack = new Rack$1({ - blade: config.root ? undefined : config.blade, - viewProps: config.viewProps, - }); - rack.emitter.on('add', this.onRackAdd_); - rack.emitter.on('remove', this.onRackRemove_); - this.rack = rack; - this.viewProps.handleDispose(() => { - for (let i = this.rack.children.length - 1; i >= 0; i--) { - const bc = this.rack.children[i]; - bc.viewProps.set('disposed', true); - } - }); - } - onRackAdd_(ev) { - if (!ev.root) { - return; - } - insertElementAt$1(this.element, ev.bladeController.view.element, ev.index); - } - onRackRemove_(ev) { - if (!ev.root) { - return; - } - removeElement$1(ev.bladeController.view.element); - } - } - - function createBlade$1() { - return new ValueMap$1({ - positions: createValue$1([], { - equals: deepEqualsArray$1, - }), - }); - } - - class Foldable$1 extends ValueMap$1 { - constructor(valueMap) { - super(valueMap); - } - static create(expanded) { - const coreObj = { - completed: true, - expanded: expanded, - expandedHeight: null, - shouldFixHeight: false, - temporaryExpanded: null, - }; - const core = ValueMap$1.createCore(coreObj); - return new Foldable$1(core); - } - get styleExpanded() { - var _a; - return (_a = this.get('temporaryExpanded')) !== null && _a !== void 0 ? _a : this.get('expanded'); - } - get styleHeight() { - if (!this.styleExpanded) { - return '0'; - } - const exHeight = this.get('expandedHeight'); - if (this.get('shouldFixHeight') && !isEmpty$1(exHeight)) { - return `${exHeight}px`; - } - return 'auto'; - } - bindExpandedClass(elem, expandedClassName) { - const onExpand = () => { - const expanded = this.styleExpanded; - if (expanded) { - elem.classList.add(expandedClassName); - } - else { - elem.classList.remove(expandedClassName); - } - }; - bindValueMap$1(this, 'expanded', onExpand); - bindValueMap$1(this, 'temporaryExpanded', onExpand); - } - cleanUpTransition() { - this.set('shouldFixHeight', false); - this.set('expandedHeight', null); - this.set('completed', true); - } - } - function computeExpandedFolderHeight$1(folder, containerElement) { - let height = 0; - disableTransitionTemporarily$1(containerElement, () => { - folder.set('expandedHeight', null); - folder.set('temporaryExpanded', true); - forceReflow$1(containerElement); - height = containerElement.clientHeight; - folder.set('temporaryExpanded', null); - forceReflow$1(containerElement); - }); - return height; - } - function applyHeight$1(foldable, elem) { - elem.style.height = foldable.styleHeight; - } - function bindFoldable$1(foldable, elem) { - foldable.value('expanded').emitter.on('beforechange', () => { - foldable.set('completed', false); - if (isEmpty$1(foldable.get('expandedHeight'))) { - const h = computeExpandedFolderHeight$1(foldable, elem); - if (h > 0) { - foldable.set('expandedHeight', h); - } - } - foldable.set('shouldFixHeight', true); - forceReflow$1(elem); - }); - foldable.emitter.on('change', () => { - applyHeight$1(foldable, elem); - }); - applyHeight$1(foldable, elem); - elem.addEventListener('transitionend', (ev) => { - if (ev.propertyName !== 'height') { - return; - } - foldable.cleanUpTransition(); - }); - } - - class FolderApi$1 extends ContainerBladeApi$1 { - constructor(controller, pool) { - super(controller, pool); - this.emitter_ = new Emitter$1(); - this.controller.foldable - .value('expanded') - .emitter.on('change', (ev) => { - this.emitter_.emit('fold', new TpFoldEvent$1(this, ev.sender.rawValue)); - }); - this.rackApi_.on('change', (ev) => { - this.emitter_.emit('change', ev); - }); - } - get expanded() { - return this.controller.foldable.get('expanded'); - } - set expanded(expanded) { - this.controller.foldable.set('expanded', expanded); - } - get title() { - return this.controller.props.get('title'); - } - set title(title) { - this.controller.props.set('title', title); - } - get children() { - return this.rackApi_.children; - } - addBinding(object, key, opt_params) { - return this.rackApi_.addBinding(object, key, opt_params); - } - addFolder(params) { - return this.rackApi_.addFolder(params); - } - addButton(params) { - return this.rackApi_.addButton(params); - } - addTab(params) { - return this.rackApi_.addTab(params); - } - add(api, opt_index) { - return this.rackApi_.add(api, opt_index); - } - remove(api) { - this.rackApi_.remove(api); - } - addBlade(params) { - return this.rackApi_.addBlade(params); - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }, { - key: handler, - }); - return this; - } - off(eventName, handler) { - this.emitter_.off(eventName, handler); - return this; - } - } - - const bladeContainerClassName$1 = ClassName$1('cnt'); - - class FolderView$1 { - constructor(doc, config) { - var _a; - this.className_ = ClassName$1((_a = config.viewName) !== null && _a !== void 0 ? _a : 'fld'); - this.element = doc.createElement('div'); - this.element.classList.add(this.className_(), bladeContainerClassName$1()); - config.viewProps.bindClassModifiers(this.element); - this.foldable_ = config.foldable; - this.foldable_.bindExpandedClass(this.element, this.className_(undefined, 'expanded')); - bindValueMap$1(this.foldable_, 'completed', valueToClassName$1(this.element, this.className_(undefined, 'cpl'))); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(this.className_('b')); - bindValueMap$1(config.props, 'title', (title) => { - if (isEmpty$1(title)) { - this.element.classList.add(this.className_(undefined, 'not')); - } - else { - this.element.classList.remove(this.className_(undefined, 'not')); - } - }); - config.viewProps.bindDisabled(buttonElem); - this.element.appendChild(buttonElem); - this.buttonElement = buttonElem; - const indentElem = doc.createElement('div'); - indentElem.classList.add(this.className_('i')); - this.element.appendChild(indentElem); - const titleElem = doc.createElement('div'); - titleElem.classList.add(this.className_('t')); - bindValueToTextContent$1(config.props.value('title'), titleElem); - this.buttonElement.appendChild(titleElem); - this.titleElement = titleElem; - const markElem = doc.createElement('div'); - markElem.classList.add(this.className_('m')); - this.buttonElement.appendChild(markElem); - const containerElem = doc.createElement('div'); - containerElem.classList.add(this.className_('c')); - this.element.appendChild(containerElem); - this.containerElement = containerElem; - } - } - - class FolderController$1 extends ContainerBladeController$1 { - constructor(doc, config) { - var _a; - const foldable = Foldable$1.create((_a = config.expanded) !== null && _a !== void 0 ? _a : true); - const view = new FolderView$1(doc, { - foldable: foldable, - props: config.props, - viewName: config.root ? 'rot' : undefined, - viewProps: config.viewProps, - }); - super(Object.assign(Object.assign({}, config), { rackController: new RackController$1({ - blade: config.blade, - element: view.containerElement, - root: config.root, - viewProps: config.viewProps, - }), view: view })); - this.onTitleClick_ = this.onTitleClick_.bind(this); - this.props = config.props; - this.foldable = foldable; - bindFoldable$1(this.foldable, this.view.containerElement); - this.rackController.rack.emitter.on('add', () => { - this.foldable.cleanUpTransition(); - }); - this.rackController.rack.emitter.on('remove', () => { - this.foldable.cleanUpTransition(); - }); - this.view.buttonElement.addEventListener('click', this.onTitleClick_); - } - get document() { - return this.view.element.ownerDocument; - } - importState(state) { - return importBladeState$1(state, (s) => super.importState(s), (p) => ({ - expanded: p.required.boolean, - title: p.optional.string, - }), (result) => { - this.foldable.set('expanded', result.expanded); - this.props.set('title', result.title); - return true; - }); - } - exportState() { - return exportBladeState$1(() => super.exportState(), { - expanded: this.foldable.get('expanded'), - title: this.props.get('title'), - }); - } - onTitleClick_() { - this.foldable.set('expanded', !this.foldable.get('expanded')); - } - } - - const FolderBladePlugin = createPlugin$1({ - id: 'folder', - type: 'blade', - accept(params) { - const result = parseRecord$1(params, (p) => ({ - title: p.required.string, - view: p.required.constant('folder'), - expanded: p.optional.boolean, - })); - return result ? { params: result } : null; - }, - controller(args) { - return new FolderController$1(args.document, { - blade: args.blade, - expanded: args.params.expanded, - props: ValueMap$1.fromObject({ - title: args.params.title, - }), - viewProps: args.viewProps, - }); - }, - api(args) { - if (!(args.controller instanceof FolderController$1)) { - return null; - } - return new FolderApi$1(args.controller, args.pool); - }, - }); - - const cn$o$1 = ClassName$1(''); - function valueToModifier$1(elem, modifier) { - return valueToClassName$1(elem, cn$o$1(undefined, modifier)); - } - class ViewProps$1 extends ValueMap$1 { - constructor(valueMap) { - var _a; - super(valueMap); - this.onDisabledChange_ = this.onDisabledChange_.bind(this); - this.onParentChange_ = this.onParentChange_.bind(this); - this.onParentGlobalDisabledChange_ = - this.onParentGlobalDisabledChange_.bind(this); - [this.globalDisabled_, this.setGlobalDisabled_] = createReadonlyValue$1(createValue$1(this.getGlobalDisabled_())); - this.value('disabled').emitter.on('change', this.onDisabledChange_); - this.value('parent').emitter.on('change', this.onParentChange_); - (_a = this.get('parent')) === null || _a === void 0 ? void 0 : _a.globalDisabled.emitter.on('change', this.onParentGlobalDisabledChange_); - } - static create(opt_initialValue) { - var _a, _b, _c; - const initialValue = opt_initialValue !== null && opt_initialValue !== void 0 ? opt_initialValue : {}; - return new ViewProps$1(ValueMap$1.createCore({ - disabled: (_a = initialValue.disabled) !== null && _a !== void 0 ? _a : false, - disposed: false, - hidden: (_b = initialValue.hidden) !== null && _b !== void 0 ? _b : false, - parent: (_c = initialValue.parent) !== null && _c !== void 0 ? _c : null, - })); - } - get globalDisabled() { - return this.globalDisabled_; - } - bindClassModifiers(elem) { - bindValue$1(this.globalDisabled_, valueToModifier$1(elem, 'disabled')); - bindValueMap$1(this, 'hidden', valueToModifier$1(elem, 'hidden')); - } - bindDisabled(target) { - bindValue$1(this.globalDisabled_, (disabled) => { - target.disabled = disabled; - }); - } - bindTabIndex(elem) { - bindValue$1(this.globalDisabled_, (disabled) => { - elem.tabIndex = disabled ? -1 : 0; - }); - } - handleDispose(callback) { - this.value('disposed').emitter.on('change', (disposed) => { - if (disposed) { - callback(); - } - }); - } - importState(state) { - this.set('disabled', state.disabled); - this.set('hidden', state.hidden); - } - exportState() { - return { - disabled: this.get('disabled'), - hidden: this.get('hidden'), - }; - } - getGlobalDisabled_() { - const parent = this.get('parent'); - const parentDisabled = parent ? parent.globalDisabled.rawValue : false; - return parentDisabled || this.get('disabled'); - } - updateGlobalDisabled_() { - this.setGlobalDisabled_(this.getGlobalDisabled_()); - } - onDisabledChange_() { - this.updateGlobalDisabled_(); - } - onParentGlobalDisabledChange_() { - this.updateGlobalDisabled_(); - } - onParentChange_(ev) { - var _a; - const prevParent = ev.previousRawValue; - prevParent === null || prevParent === void 0 ? void 0 : prevParent.globalDisabled.emitter.off('change', this.onParentGlobalDisabledChange_); - (_a = this.get('parent')) === null || _a === void 0 ? void 0 : _a.globalDisabled.emitter.on('change', this.onParentGlobalDisabledChange_); - this.updateGlobalDisabled_(); - } - } - - const cn$n$1 = ClassName$1('tbp'); - class TabPageView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$n$1()); - config.viewProps.bindClassModifiers(this.element); - const containerElem = doc.createElement('div'); - containerElem.classList.add(cn$n$1('c')); - this.element.appendChild(containerElem); - this.containerElement = containerElem; - } - } - - const cn$m$1 = ClassName$1('tbi'); - class TabItemView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$m$1()); - config.viewProps.bindClassModifiers(this.element); - bindValueMap$1(config.props, 'selected', (selected) => { - if (selected) { - this.element.classList.add(cn$m$1(undefined, 'sel')); - } - else { - this.element.classList.remove(cn$m$1(undefined, 'sel')); - } - }); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(cn$m$1('b')); - config.viewProps.bindDisabled(buttonElem); - this.element.appendChild(buttonElem); - this.buttonElement = buttonElem; - const titleElem = doc.createElement('div'); - titleElem.classList.add(cn$m$1('t')); - bindValueToTextContent$1(config.props.value('title'), titleElem); - this.buttonElement.appendChild(titleElem); - this.titleElement = titleElem; - } - } - - class TabItemController$1 { - constructor(doc, config) { - this.emitter = new Emitter$1(); - this.onClick_ = this.onClick_.bind(this); - this.props = config.props; - this.viewProps = config.viewProps; - this.view = new TabItemView$1(doc, { - props: config.props, - viewProps: config.viewProps, - }); - this.view.buttonElement.addEventListener('click', this.onClick_); - } - onClick_() { - this.emitter.emit('click', { - sender: this, - }); - } - } - - class TabPageController$1 extends ContainerBladeController$1 { - constructor(doc, config) { - const view = new TabPageView$1(doc, { - viewProps: config.viewProps, - }); - super(Object.assign(Object.assign({}, config), { rackController: new RackController$1({ - blade: config.blade, - element: view.containerElement, - viewProps: config.viewProps, - }), view: view })); - this.onItemClick_ = this.onItemClick_.bind(this); - this.ic_ = new TabItemController$1(doc, { - props: config.itemProps, - viewProps: ViewProps$1.create(), - }); - this.ic_.emitter.on('click', this.onItemClick_); - this.props = config.props; - bindValueMap$1(this.props, 'selected', (selected) => { - this.itemController.props.set('selected', selected); - this.viewProps.set('hidden', !selected); - }); - } - get itemController() { - return this.ic_; - } - importState(state) { - return importBladeState$1(state, (s) => super.importState(s), (p) => ({ - selected: p.required.boolean, - title: p.required.string, - }), (result) => { - this.ic_.props.set('selected', result.selected); - this.ic_.props.set('title', result.title); - return true; - }); - } - exportState() { - return exportBladeState$1(() => super.exportState(), { - selected: this.ic_.props.get('selected'), - title: this.ic_.props.get('title'), - }); - } - onItemClick_() { - this.props.set('selected', true); - } - } - - class TabApi$1 extends ContainerBladeApi$1 { - constructor(controller, pool) { - super(controller, pool); - this.emitter_ = new Emitter$1(); - this.onSelect_ = this.onSelect_.bind(this); - this.pool_ = pool; - this.rackApi_.on('change', (ev) => { - this.emitter_.emit('change', ev); - }); - this.controller.tab.selectedIndex.emitter.on('change', this.onSelect_); - } - get pages() { - return this.rackApi_.children; - } - addPage(params) { - const doc = this.controller.view.element.ownerDocument; - const pc = new TabPageController$1(doc, { - blade: createBlade$1(), - itemProps: ValueMap$1.fromObject({ - selected: false, - title: params.title, - }), - props: ValueMap$1.fromObject({ - selected: false, - }), - viewProps: ViewProps$1.create(), - }); - const papi = this.pool_.createApi(pc); - return this.rackApi_.add(papi, params.index); - } - removePage(index) { - this.rackApi_.remove(this.rackApi_.children[index]); - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }, { - key: handler, - }); - return this; - } - off(eventName, handler) { - this.emitter_.off(eventName, handler); - return this; - } - onSelect_(ev) { - this.emitter_.emit('select', new TpTabSelectEvent$1(this, ev.rawValue)); - } - } - - class TabPageApi$1 extends ContainerBladeApi$1 { - get title() { - var _a; - return (_a = this.controller.itemController.props.get('title')) !== null && _a !== void 0 ? _a : ''; - } - set title(title) { - this.controller.itemController.props.set('title', title); - } - get selected() { - return this.controller.props.get('selected'); - } - set selected(selected) { - this.controller.props.set('selected', selected); - } - get children() { - return this.rackApi_.children; - } - addButton(params) { - return this.rackApi_.addButton(params); - } - addFolder(params) { - return this.rackApi_.addFolder(params); - } - addTab(params) { - return this.rackApi_.addTab(params); - } - add(api, opt_index) { - this.rackApi_.add(api, opt_index); - } - remove(api) { - this.rackApi_.remove(api); - } - addBinding(object, key, opt_params) { - return this.rackApi_.addBinding(object, key, opt_params); - } - addBlade(params) { - return this.rackApi_.addBlade(params); - } - } - - const INDEX_NOT_SELECTED$1 = -1; - class Tab$1 { - constructor() { - this.onItemSelectedChange_ = this.onItemSelectedChange_.bind(this); - this.empty = createValue$1(true); - this.selectedIndex = createValue$1(INDEX_NOT_SELECTED$1); - this.items_ = []; - } - add(item, opt_index) { - const index = opt_index !== null && opt_index !== void 0 ? opt_index : this.items_.length; - this.items_.splice(index, 0, item); - item.emitter.on('change', this.onItemSelectedChange_); - this.keepSelection_(); - } - remove(item) { - const index = this.items_.indexOf(item); - if (index < 0) { - return; - } - this.items_.splice(index, 1); - item.emitter.off('change', this.onItemSelectedChange_); - this.keepSelection_(); - } - keepSelection_() { - if (this.items_.length === 0) { - this.selectedIndex.rawValue = INDEX_NOT_SELECTED$1; - this.empty.rawValue = true; - return; - } - const firstSelIndex = this.items_.findIndex((s) => s.rawValue); - if (firstSelIndex < 0) { - this.items_.forEach((s, i) => { - s.rawValue = i === 0; - }); - this.selectedIndex.rawValue = 0; - } - else { - this.items_.forEach((s, i) => { - s.rawValue = i === firstSelIndex; - }); - this.selectedIndex.rawValue = firstSelIndex; - } - this.empty.rawValue = false; - } - onItemSelectedChange_(ev) { - if (ev.rawValue) { - const index = this.items_.findIndex((s) => s === ev.sender); - this.items_.forEach((s, i) => { - s.rawValue = i === index; - }); - this.selectedIndex.rawValue = index; - } - else { - this.keepSelection_(); - } - } - } - - const cn$l$1 = ClassName$1('tab'); - class TabView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$l$1(), bladeContainerClassName$1()); - config.viewProps.bindClassModifiers(this.element); - bindValue$1(config.empty, valueToClassName$1(this.element, cn$l$1(undefined, 'nop'))); - const titleElem = doc.createElement('div'); - titleElem.classList.add(cn$l$1('t')); - this.element.appendChild(titleElem); - this.itemsElement = titleElem; - const indentElem = doc.createElement('div'); - indentElem.classList.add(cn$l$1('i')); - this.element.appendChild(indentElem); - const contentsElem = doc.createElement('div'); - contentsElem.classList.add(cn$l$1('c')); - this.element.appendChild(contentsElem); - this.contentsElement = contentsElem; - } - } - - class TabController$1 extends ContainerBladeController$1 { - constructor(doc, config) { - const tab = new Tab$1(); - const view = new TabView$1(doc, { - empty: tab.empty, - viewProps: config.viewProps, - }); - super({ - blade: config.blade, - rackController: new RackController$1({ - blade: config.blade, - element: view.contentsElement, - viewProps: config.viewProps, - }), - view: view, - }); - this.onRackAdd_ = this.onRackAdd_.bind(this); - this.onRackRemove_ = this.onRackRemove_.bind(this); - const rack = this.rackController.rack; - rack.emitter.on('add', this.onRackAdd_); - rack.emitter.on('remove', this.onRackRemove_); - this.tab = tab; - } - add(pc, opt_index) { - this.rackController.rack.add(pc, opt_index); - } - remove(index) { - this.rackController.rack.remove(this.rackController.rack.children[index]); - } - onRackAdd_(ev) { - if (!ev.root) { - return; - } - const pc = ev.bladeController; - insertElementAt$1(this.view.itemsElement, pc.itemController.view.element, ev.index); - pc.itemController.viewProps.set('parent', this.viewProps); - this.tab.add(pc.props.value('selected')); - } - onRackRemove_(ev) { - if (!ev.root) { - return; - } - const pc = ev.bladeController; - removeElement$1(pc.itemController.view.element); - pc.itemController.viewProps.set('parent', null); - this.tab.remove(pc.props.value('selected')); - } - } - - const TabBladePlugin = createPlugin$1({ - id: 'tab', - type: 'blade', - accept(params) { - const result = parseRecord$1(params, (p) => ({ - pages: p.required.array(p.required.object({ title: p.required.string })), - view: p.required.constant('tab'), - })); - if (!result || result.pages.length === 0) { - return null; - } - return { params: result }; - }, - controller(args) { - const c = new TabController$1(args.document, { - blade: args.blade, - viewProps: args.viewProps, - }); - args.params.pages.forEach((p) => { - const pc = new TabPageController$1(args.document, { - blade: createBlade$1(), - itemProps: ValueMap$1.fromObject({ - selected: false, - title: p.title, - }), - props: ValueMap$1.fromObject({ - selected: false, - }), - viewProps: ViewProps$1.create(), - }); - c.add(pc); - }); - return c; - }, - api(args) { - if (args.controller instanceof TabController$1) { - return new TabApi$1(args.controller, args.pool); - } - if (args.controller instanceof TabPageController$1) { - return new TabPageApi$1(args.controller, args.pool); - } - return null; - }, - }); - - function createBladeController(plugin, args) { - const ac = plugin.accept(args.params); - if (!ac) { - return null; - } - const params = parseRecord$1(args.params, (p) => ({ - disabled: p.optional.boolean, - hidden: p.optional.boolean, - })); - return plugin.controller({ - blade: createBlade$1(), - document: args.document, - params: forceCast$1(Object.assign(Object.assign({}, ac.params), { disabled: params === null || params === void 0 ? void 0 : params.disabled, hidden: params === null || params === void 0 ? void 0 : params.hidden })), - viewProps: ViewProps$1.create({ - disabled: params === null || params === void 0 ? void 0 : params.disabled, - hidden: params === null || params === void 0 ? void 0 : params.hidden, - }), - }); - } - - class ListInputBindingApi$1 extends BindingApi$1 { - get options() { - return this.controller.valueController.props.get('options'); - } - set options(options) { - this.controller.valueController.props.set('options', options); - } - } - - class ManualTicker$1 { - constructor() { - this.disabled = false; - this.emitter = new Emitter$1(); - } - dispose() { } - tick() { - if (this.disabled) { - return; - } - this.emitter.emit('tick', { - sender: this, - }); - } - } - - class IntervalTicker$1 { - constructor(doc, interval) { - this.disabled_ = false; - this.timerId_ = null; - this.onTick_ = this.onTick_.bind(this); - this.doc_ = doc; - this.emitter = new Emitter$1(); - this.interval_ = interval; - this.setTimer_(); - } - get disabled() { - return this.disabled_; - } - set disabled(inactive) { - this.disabled_ = inactive; - if (this.disabled_) { - this.clearTimer_(); - } - else { - this.setTimer_(); - } - } - dispose() { - this.clearTimer_(); - } - clearTimer_() { - if (this.timerId_ === null) { - return; - } - const win = this.doc_.defaultView; - if (win) { - win.clearInterval(this.timerId_); - } - this.timerId_ = null; - } - setTimer_() { - this.clearTimer_(); - if (this.interval_ <= 0) { - return; - } - const win = this.doc_.defaultView; - if (win) { - this.timerId_ = win.setInterval(this.onTick_, this.interval_); - } - } - onTick_() { - if (this.disabled_) { - return; - } - this.emitter.emit('tick', { - sender: this, - }); - } - } - - class CompositeConstraint$1 { - constructor(constraints) { - this.constraints = constraints; - } - constrain(value) { - return this.constraints.reduce((result, c) => { - return c.constrain(result); - }, value); - } - } - function findConstraint$1(c, constraintClass) { - if (c instanceof constraintClass) { - return c; - } - if (c instanceof CompositeConstraint$1) { - const result = c.constraints.reduce((tmpResult, sc) => { - if (tmpResult) { - return tmpResult; - } - return sc instanceof constraintClass ? sc : null; - }, null); - if (result) { - return result; - } - } - return null; - } - - class ListConstraint$1 { - constructor(options) { - this.values = ValueMap$1.fromObject({ - options: options, - }); - } - constrain(value) { - const opts = this.values.get('options'); - if (opts.length === 0) { - return value; - } - const matched = opts.filter((item) => { - return item.value === value; - }).length > 0; - return matched ? value : opts[0].value; - } - } - - function parseListOptions$1(value) { - var _a; - const p = MicroParsers$1; - if (Array.isArray(value)) { - return (_a = parseRecord$1({ items: value }, (p) => ({ - items: p.required.array(p.required.object({ - text: p.required.string, - value: p.required.raw, - })), - }))) === null || _a === void 0 ? void 0 : _a.items; - } - if (typeof value === 'object') { - return p.required.raw(value) - .value; - } - return undefined; - } - function normalizeListOptions$1(options) { - if (Array.isArray(options)) { - return options; - } - const items = []; - Object.keys(options).forEach((text) => { - items.push({ text: text, value: options[text] }); - }); - return items; - } - function createListConstraint$1(options) { - return !isEmpty$1(options) - ? new ListConstraint$1(normalizeListOptions$1(forceCast$1(options))) - : null; - } - - const cn$k$1 = ClassName$1('lst'); - class ListView$1 { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.props_ = config.props; - this.element = doc.createElement('div'); - this.element.classList.add(cn$k$1()); - config.viewProps.bindClassModifiers(this.element); - const selectElem = doc.createElement('select'); - selectElem.classList.add(cn$k$1('s')); - config.viewProps.bindDisabled(selectElem); - this.element.appendChild(selectElem); - this.selectElement = selectElem; - const markElem = doc.createElement('div'); - markElem.classList.add(cn$k$1('m')); - markElem.appendChild(createSvgIconElement$1(doc, 'dropdown')); - this.element.appendChild(markElem); - config.value.emitter.on('change', this.onValueChange_); - this.value_ = config.value; - bindValueMap$1(this.props_, 'options', (opts) => { - removeChildElements$1(this.selectElement); - opts.forEach((item) => { - const optionElem = doc.createElement('option'); - optionElem.textContent = item.text; - this.selectElement.appendChild(optionElem); - }); - this.update_(); - }); - } - update_() { - const values = this.props_.get('options').map((o) => o.value); - this.selectElement.selectedIndex = values.indexOf(this.value_.rawValue); - } - onValueChange_() { - this.update_(); - } - } - - class ListController$1 { - constructor(doc, config) { - this.onSelectChange_ = this.onSelectChange_.bind(this); - this.props = config.props; - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new ListView$1(doc, { - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - this.view.selectElement.addEventListener('change', this.onSelectChange_); - } - onSelectChange_(e) { - const selectElem = forceCast$1(e.currentTarget); - this.value.rawValue = - this.props.get('options')[selectElem.selectedIndex].value; - } - importProps(state) { - return importBladeState$1(state, null, (p) => ({ - options: p.required.custom(parseListOptions$1), - }), (result) => { - this.props.set('options', normalizeListOptions$1(result.options)); - return true; - }); - } - exportProps() { - return exportBladeState$1(null, { - options: this.props.get('options'), - }); - } - } - - const cn$j$1 = ClassName$1('pop'); - class PopupView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$j$1()); - config.viewProps.bindClassModifiers(this.element); - bindValue$1(config.shows, valueToClassName$1(this.element, cn$j$1(undefined, 'v'))); - } - } - - class PopupController$1 { - constructor(doc, config) { - this.shows = createValue$1(false); - this.viewProps = config.viewProps; - this.view = new PopupView$1(doc, { - shows: this.shows, - viewProps: this.viewProps, - }); - } - } - - const cn$i$1 = ClassName$1('txt'); - class TextView$1 { - constructor(doc, config) { - this.onChange_ = this.onChange_.bind(this); - this.element = doc.createElement('div'); - this.element.classList.add(cn$i$1()); - config.viewProps.bindClassModifiers(this.element); - this.props_ = config.props; - this.props_.emitter.on('change', this.onChange_); - const inputElem = doc.createElement('input'); - inputElem.classList.add(cn$i$1('i')); - inputElem.type = 'text'; - config.viewProps.bindDisabled(inputElem); - this.element.appendChild(inputElem); - this.inputElement = inputElem; - config.value.emitter.on('change', this.onChange_); - this.value_ = config.value; - this.refresh(); - } - refresh() { - const formatter = this.props_.get('formatter'); - this.inputElement.value = formatter(this.value_.rawValue); - } - onChange_() { - this.refresh(); - } - } - - class TextController$1 { - constructor(doc, config) { - this.onInputChange_ = this.onInputChange_.bind(this); - this.parser_ = config.parser; - this.props = config.props; - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new TextView$1(doc, { - props: config.props, - value: this.value, - viewProps: this.viewProps, - }); - this.view.inputElement.addEventListener('change', this.onInputChange_); - } - onInputChange_(e) { - const inputElem = forceCast$1(e.currentTarget); - const value = inputElem.value; - const parsedValue = this.parser_(value); - if (!isEmpty$1(parsedValue)) { - this.value.rawValue = parsedValue; - } - this.view.refresh(); - } - } - - function boolToString$1(value) { - return String(value); - } - function boolFromUnknown$1(value) { - if (value === 'false') { - return false; - } - return !!value; - } - function BooleanFormatter$1(value) { - return boolToString$1(value); - } - - function composeParsers$1(parsers) { - return (text) => { - return parsers.reduce((result, parser) => { - if (result !== null) { - return result; - } - return parser(text); - }, null); - }; - } - - const innerFormatter$1 = createNumberFormatter$1(0); - function formatPercentage$1(value) { - return innerFormatter$1(value) + '%'; - } - - function stringFromUnknown$1(value) { - return String(value); - } - function formatString$1(value) { - return value; - } - - function connectValues$1({ primary, secondary, forward, backward, }) { - let changing = false; - function preventFeedback(callback) { - if (changing) { - return; - } - changing = true; - callback(); - changing = false; - } - primary.emitter.on('change', (ev) => { - preventFeedback(() => { - secondary.setRawValue(forward(primary.rawValue, secondary.rawValue), ev.options); - }); - }); - secondary.emitter.on('change', (ev) => { - preventFeedback(() => { - primary.setRawValue(backward(primary.rawValue, secondary.rawValue), ev.options); - }); - preventFeedback(() => { - secondary.setRawValue(forward(primary.rawValue, secondary.rawValue), ev.options); - }); - }); - preventFeedback(() => { - secondary.setRawValue(forward(primary.rawValue, secondary.rawValue), { - forceEmit: false, - last: true, - }); - }); - } - - function getStepForKey$1(keyScale, keys) { - const step = keyScale * (keys.altKey ? 0.1 : 1) * (keys.shiftKey ? 10 : 1); - if (keys.upKey) { - return +step; - } - else if (keys.downKey) { - return -step; - } - return 0; - } - function getVerticalStepKeys$1(ev) { - return { - altKey: ev.altKey, - downKey: ev.key === 'ArrowDown', - shiftKey: ev.shiftKey, - upKey: ev.key === 'ArrowUp', - }; - } - function getHorizontalStepKeys$1(ev) { - return { - altKey: ev.altKey, - downKey: ev.key === 'ArrowLeft', - shiftKey: ev.shiftKey, - upKey: ev.key === 'ArrowRight', - }; - } - function isVerticalArrowKey$1(key) { - return key === 'ArrowUp' || key === 'ArrowDown'; - } - function isArrowKey$1(key) { - return isVerticalArrowKey$1(key) || key === 'ArrowLeft' || key === 'ArrowRight'; - } - - function computeOffset$1$1(ev, elem) { - var _a, _b; - const win = elem.ownerDocument.defaultView; - const rect = elem.getBoundingClientRect(); - return { - x: ev.pageX - (((_a = (win && win.scrollX)) !== null && _a !== void 0 ? _a : 0) + rect.left), - y: ev.pageY - (((_b = (win && win.scrollY)) !== null && _b !== void 0 ? _b : 0) + rect.top), - }; - } - class PointerHandler$1 { - constructor(element) { - this.lastTouch_ = null; - this.onDocumentMouseMove_ = this.onDocumentMouseMove_.bind(this); - this.onDocumentMouseUp_ = this.onDocumentMouseUp_.bind(this); - this.onMouseDown_ = this.onMouseDown_.bind(this); - this.onTouchEnd_ = this.onTouchEnd_.bind(this); - this.onTouchMove_ = this.onTouchMove_.bind(this); - this.onTouchStart_ = this.onTouchStart_.bind(this); - this.elem_ = element; - this.emitter = new Emitter$1(); - element.addEventListener('touchstart', this.onTouchStart_, { - passive: false, - }); - element.addEventListener('touchmove', this.onTouchMove_, { - passive: true, - }); - element.addEventListener('touchend', this.onTouchEnd_); - element.addEventListener('mousedown', this.onMouseDown_); - } - computePosition_(offset) { - const rect = this.elem_.getBoundingClientRect(); - return { - bounds: { - width: rect.width, - height: rect.height, - }, - point: offset - ? { - x: offset.x, - y: offset.y, - } - : null, - }; - } - onMouseDown_(ev) { - var _a; - ev.preventDefault(); - (_a = ev.currentTarget) === null || _a === void 0 ? void 0 : _a.focus(); - const doc = this.elem_.ownerDocument; - doc.addEventListener('mousemove', this.onDocumentMouseMove_); - doc.addEventListener('mouseup', this.onDocumentMouseUp_); - this.emitter.emit('down', { - altKey: ev.altKey, - data: this.computePosition_(computeOffset$1$1(ev, this.elem_)), - sender: this, - shiftKey: ev.shiftKey, - }); - } - onDocumentMouseMove_(ev) { - this.emitter.emit('move', { - altKey: ev.altKey, - data: this.computePosition_(computeOffset$1$1(ev, this.elem_)), - sender: this, - shiftKey: ev.shiftKey, - }); - } - onDocumentMouseUp_(ev) { - const doc = this.elem_.ownerDocument; - doc.removeEventListener('mousemove', this.onDocumentMouseMove_); - doc.removeEventListener('mouseup', this.onDocumentMouseUp_); - this.emitter.emit('up', { - altKey: ev.altKey, - data: this.computePosition_(computeOffset$1$1(ev, this.elem_)), - sender: this, - shiftKey: ev.shiftKey, - }); - } - onTouchStart_(ev) { - ev.preventDefault(); - const touch = ev.targetTouches.item(0); - const rect = this.elem_.getBoundingClientRect(); - this.emitter.emit('down', { - altKey: ev.altKey, - data: this.computePosition_(touch - ? { - x: touch.clientX - rect.left, - y: touch.clientY - rect.top, - } - : undefined), - sender: this, - shiftKey: ev.shiftKey, - }); - this.lastTouch_ = touch; - } - onTouchMove_(ev) { - const touch = ev.targetTouches.item(0); - const rect = this.elem_.getBoundingClientRect(); - this.emitter.emit('move', { - altKey: ev.altKey, - data: this.computePosition_(touch - ? { - x: touch.clientX - rect.left, - y: touch.clientY - rect.top, - } - : undefined), - sender: this, - shiftKey: ev.shiftKey, - }); - this.lastTouch_ = touch; - } - onTouchEnd_(ev) { - var _a; - const touch = (_a = ev.targetTouches.item(0)) !== null && _a !== void 0 ? _a : this.lastTouch_; - const rect = this.elem_.getBoundingClientRect(); - this.emitter.emit('up', { - altKey: ev.altKey, - data: this.computePosition_(touch - ? { - x: touch.clientX - rect.left, - y: touch.clientY - rect.top, - } - : undefined), - sender: this, - shiftKey: ev.shiftKey, - }); - } - } - - const cn$h$1 = ClassName$1('txt'); - class NumberTextView$1 { - constructor(doc, config) { - this.onChange_ = this.onChange_.bind(this); - this.props_ = config.props; - this.props_.emitter.on('change', this.onChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$h$1(), cn$h$1(undefined, 'num')); - if (config.arrayPosition) { - this.element.classList.add(cn$h$1(undefined, config.arrayPosition)); - } - config.viewProps.bindClassModifiers(this.element); - const inputElem = doc.createElement('input'); - inputElem.classList.add(cn$h$1('i')); - inputElem.type = 'text'; - config.viewProps.bindDisabled(inputElem); - this.element.appendChild(inputElem); - this.inputElement = inputElem; - this.onDraggingChange_ = this.onDraggingChange_.bind(this); - this.dragging_ = config.dragging; - this.dragging_.emitter.on('change', this.onDraggingChange_); - this.element.classList.add(cn$h$1()); - this.inputElement.classList.add(cn$h$1('i')); - const knobElem = doc.createElement('div'); - knobElem.classList.add(cn$h$1('k')); - this.element.appendChild(knobElem); - this.knobElement = knobElem; - const guideElem = doc.createElementNS(SVG_NS$1, 'svg'); - guideElem.classList.add(cn$h$1('g')); - this.knobElement.appendChild(guideElem); - const bodyElem = doc.createElementNS(SVG_NS$1, 'path'); - bodyElem.classList.add(cn$h$1('gb')); - guideElem.appendChild(bodyElem); - this.guideBodyElem_ = bodyElem; - const headElem = doc.createElementNS(SVG_NS$1, 'path'); - headElem.classList.add(cn$h$1('gh')); - guideElem.appendChild(headElem); - this.guideHeadElem_ = headElem; - const tooltipElem = doc.createElement('div'); - tooltipElem.classList.add(ClassName$1('tt')()); - this.knobElement.appendChild(tooltipElem); - this.tooltipElem_ = tooltipElem; - config.value.emitter.on('change', this.onChange_); - this.value = config.value; - this.refresh(); - } - onDraggingChange_(ev) { - if (ev.rawValue === null) { - this.element.classList.remove(cn$h$1(undefined, 'drg')); - return; - } - this.element.classList.add(cn$h$1(undefined, 'drg')); - const x = ev.rawValue / this.props_.get('pointerScale'); - const aox = x + (x > 0 ? -1 : x < 0 ? +1 : 0); - const adx = constrainRange$1(-aox, -4, +4); - this.guideHeadElem_.setAttributeNS(null, 'd', [`M ${aox + adx},0 L${aox},4 L${aox + adx},8`, `M ${x},-1 L${x},9`].join(' ')); - this.guideBodyElem_.setAttributeNS(null, 'd', `M 0,4 L${x},4`); - const formatter = this.props_.get('formatter'); - this.tooltipElem_.textContent = formatter(this.value.rawValue); - this.tooltipElem_.style.left = `${x}px`; - } - refresh() { - const formatter = this.props_.get('formatter'); - this.inputElement.value = formatter(this.value.rawValue); - } - onChange_() { - this.refresh(); - } - } - - class NumberTextController$1 { - constructor(doc, config) { - var _a; - this.originRawValue_ = 0; - this.onInputChange_ = this.onInputChange_.bind(this); - this.onInputKeyDown_ = this.onInputKeyDown_.bind(this); - this.onInputKeyUp_ = this.onInputKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.parser_ = config.parser; - this.props = config.props; - this.sliderProps_ = (_a = config.sliderProps) !== null && _a !== void 0 ? _a : null; - this.value = config.value; - this.viewProps = config.viewProps; - this.dragging_ = createValue$1(null); - this.view = new NumberTextView$1(doc, { - arrayPosition: config.arrayPosition, - dragging: this.dragging_, - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - this.view.inputElement.addEventListener('change', this.onInputChange_); - this.view.inputElement.addEventListener('keydown', this.onInputKeyDown_); - this.view.inputElement.addEventListener('keyup', this.onInputKeyUp_); - const ph = new PointerHandler$1(this.view.knobElement); - ph.emitter.on('down', this.onPointerDown_); - ph.emitter.on('move', this.onPointerMove_); - ph.emitter.on('up', this.onPointerUp_); - } - constrainValue_(value) { - var _a, _b; - const min = (_a = this.sliderProps_) === null || _a === void 0 ? void 0 : _a.get('min'); - const max = (_b = this.sliderProps_) === null || _b === void 0 ? void 0 : _b.get('max'); - let v = value; - if (min !== undefined) { - v = Math.max(v, min); - } - if (max !== undefined) { - v = Math.min(v, max); - } - return v; - } - onInputChange_(e) { - const inputElem = forceCast$1(e.currentTarget); - const value = inputElem.value; - const parsedValue = this.parser_(value); - if (!isEmpty$1(parsedValue)) { - this.value.rawValue = this.constrainValue_(parsedValue); - } - this.view.refresh(); - } - onInputKeyDown_(ev) { - const step = getStepForKey$1(this.props.get('keyScale'), getVerticalStepKeys$1(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.constrainValue_(this.value.rawValue + step), { - forceEmit: false, - last: false, - }); - } - onInputKeyUp_(ev) { - const step = getStepForKey$1(this.props.get('keyScale'), getVerticalStepKeys$1(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - onPointerDown_() { - this.originRawValue_ = this.value.rawValue; - this.dragging_.rawValue = 0; - } - computeDraggingValue_(data) { - if (!data.point) { - return null; - } - const dx = data.point.x - data.bounds.width / 2; - return this.constrainValue_(this.originRawValue_ + dx * this.props.get('pointerScale')); - } - onPointerMove_(ev) { - const v = this.computeDraggingValue_(ev.data); - if (v === null) { - return; - } - this.value.setRawValue(v, { - forceEmit: false, - last: false, - }); - this.dragging_.rawValue = this.value.rawValue - this.originRawValue_; - } - onPointerUp_(ev) { - const v = this.computeDraggingValue_(ev.data); - if (v === null) { - return; - } - this.value.setRawValue(v, { - forceEmit: true, - last: true, - }); - this.dragging_.rawValue = null; - } - } - - const cn$g$1 = ClassName$1('sld'); - class SliderView$1 { - constructor(doc, config) { - this.onChange_ = this.onChange_.bind(this); - this.props_ = config.props; - this.props_.emitter.on('change', this.onChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$g$1()); - config.viewProps.bindClassModifiers(this.element); - const trackElem = doc.createElement('div'); - trackElem.classList.add(cn$g$1('t')); - config.viewProps.bindTabIndex(trackElem); - this.element.appendChild(trackElem); - this.trackElement = trackElem; - const knobElem = doc.createElement('div'); - knobElem.classList.add(cn$g$1('k')); - this.trackElement.appendChild(knobElem); - this.knobElement = knobElem; - config.value.emitter.on('change', this.onChange_); - this.value = config.value; - this.update_(); - } - update_() { - const p = constrainRange$1(mapRange$1(this.value.rawValue, this.props_.get('min'), this.props_.get('max'), 0, 100), 0, 100); - this.knobElement.style.width = `${p}%`; - } - onChange_() { - this.update_(); - } - } - - class SliderController$1 { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDownOrMove_ = this.onPointerDownOrMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.props = config.props; - this.view = new SliderView$1(doc, { - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler$1(this.view.trackElement); - this.ptHandler_.emitter.on('down', this.onPointerDownOrMove_); - this.ptHandler_.emitter.on('move', this.onPointerDownOrMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.trackElement.addEventListener('keydown', this.onKeyDown_); - this.view.trackElement.addEventListener('keyup', this.onKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - this.value.setRawValue(mapRange$1(constrainRange$1(d.point.x, 0, d.bounds.width), 0, d.bounds.width, this.props.get('min'), this.props.get('max')), opts); - } - onPointerDownOrMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - const step = getStepForKey$1(this.props.get('keyScale'), getHorizontalStepKeys$1(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue + step, { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - const step = getStepForKey$1(this.props.get('keyScale'), getHorizontalStepKeys$1(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - const cn$f$1 = ClassName$1('sldtxt'); - class SliderTextView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$f$1()); - const sliderElem = doc.createElement('div'); - sliderElem.classList.add(cn$f$1('s')); - this.sliderView_ = config.sliderView; - sliderElem.appendChild(this.sliderView_.element); - this.element.appendChild(sliderElem); - const textElem = doc.createElement('div'); - textElem.classList.add(cn$f$1('t')); - this.textView_ = config.textView; - textElem.appendChild(this.textView_.element); - this.element.appendChild(textElem); - } - } - - class SliderTextController$1 { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.sliderC_ = new SliderController$1(doc, { - props: config.sliderProps, - value: config.value, - viewProps: this.viewProps, - }); - this.textC_ = new NumberTextController$1(doc, { - parser: config.parser, - props: config.textProps, - sliderProps: config.sliderProps, - value: config.value, - viewProps: config.viewProps, - }); - this.view = new SliderTextView$1(doc, { - sliderView: this.sliderC_.view, - textView: this.textC_.view, - }); - } - get sliderController() { - return this.sliderC_; - } - get textController() { - return this.textC_; - } - importProps(state) { - return importBladeState$1(state, null, (p) => ({ - max: p.required.number, - min: p.required.number, - }), (result) => { - const sliderProps = this.sliderC_.props; - sliderProps.set('max', result.max); - sliderProps.set('min', result.min); - return true; - }); - } - exportProps() { - const sliderProps = this.sliderC_.props; - return exportBladeState$1(null, { - max: sliderProps.get('max'), - min: sliderProps.get('min'), - }); - } - } - function createSliderTextProps$1(config) { - return { - sliderProps: new ValueMap$1({ - keyScale: config.keyScale, - max: config.max, - min: config.min, - }), - textProps: new ValueMap$1({ - formatter: createValue$1(config.formatter), - keyScale: config.keyScale, - pointerScale: createValue$1(config.pointerScale), - }), - }; - } - - const CSS_VAR_MAP$1 = { - containerUnitSize: 'cnt-usz', - }; - function getCssVar$1(key) { - return `--${CSS_VAR_MAP$1[key]}`; - } - - function createPointDimensionParser$1(p) { - return createNumberTextInputParamsParser$1(p); - } - function parsePointDimensionParams$1(value) { - if (!isRecord$1(value)) { - return undefined; - } - return parseRecord$1(value, createPointDimensionParser$1); - } - function createDimensionConstraint$1(params, initialValue) { - if (!params) { - return undefined; - } - const constraints = []; - const cs = createStepConstraint$1(params, initialValue); - if (cs) { - constraints.push(cs); - } - const rs = createRangeConstraint$1(params); - if (rs) { - constraints.push(rs); - } - return new CompositeConstraint$1(constraints); - } - - function isCompatible(ver) { - if (!ver) { - return false; - } - return ver.major === VERSION$1.major; - } - - function parsePickerLayout$1(value) { - if (value === 'inline' || value === 'popup') { - return value; - } - return undefined; - } - - function writePrimitive$1(target, value) { - target.write(value); - } - - const cn$e$1 = ClassName$1('ckb'); - class CheckboxView$1 { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.element = doc.createElement('div'); - this.element.classList.add(cn$e$1()); - config.viewProps.bindClassModifiers(this.element); - const labelElem = doc.createElement('label'); - labelElem.classList.add(cn$e$1('l')); - this.element.appendChild(labelElem); - this.labelElement = labelElem; - const inputElem = doc.createElement('input'); - inputElem.classList.add(cn$e$1('i')); - inputElem.type = 'checkbox'; - this.labelElement.appendChild(inputElem); - this.inputElement = inputElem; - config.viewProps.bindDisabled(this.inputElement); - const wrapperElem = doc.createElement('div'); - wrapperElem.classList.add(cn$e$1('w')); - this.labelElement.appendChild(wrapperElem); - const markElem = createSvgIconElement$1(doc, 'check'); - wrapperElem.appendChild(markElem); - config.value.emitter.on('change', this.onValueChange_); - this.value = config.value; - this.update_(); - } - update_() { - this.inputElement.checked = this.value.rawValue; - } - onValueChange_() { - this.update_(); - } - } - - class CheckboxController$1 { - constructor(doc, config) { - this.onInputChange_ = this.onInputChange_.bind(this); - this.onLabelMouseDown_ = this.onLabelMouseDown_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new CheckboxView$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.view.inputElement.addEventListener('change', this.onInputChange_); - this.view.labelElement.addEventListener('mousedown', this.onLabelMouseDown_); - } - onInputChange_(ev) { - const inputElem = forceCast$1(ev.currentTarget); - this.value.rawValue = inputElem.checked; - ev.preventDefault(); - ev.stopPropagation(); - } - onLabelMouseDown_(ev) { - ev.preventDefault(); - } - } - - function createConstraint$6$1(params) { - const constraints = []; - const lc = createListConstraint$1(params.options); - if (lc) { - constraints.push(lc); - } - return new CompositeConstraint$1(constraints); - } - const BooleanInputPlugin = createPlugin$1({ - id: 'input-bool', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'boolean') { - return null; - } - const result = parseRecord$1(params, (p) => ({ - options: p.optional.custom(parseListOptions$1), - readonly: p.optional.constant(false), - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => boolFromUnknown$1, - constraint: (args) => createConstraint$6$1(args.params), - writer: (_args) => writePrimitive$1, - }, - controller: (args) => { - const doc = args.document; - const value = args.value; - const c = args.constraint; - const lc = c && findConstraint$1(c, ListConstraint$1); - if (lc) { - return new ListController$1(doc, { - props: new ValueMap$1({ - options: lc.values.value('options'), - }), - value: value, - viewProps: args.viewProps, - }); - } - return new CheckboxController$1(doc, { - value: value, - viewProps: args.viewProps, - }); - }, - api(args) { - if (typeof args.controller.value.rawValue !== 'boolean') { - return null; - } - if (args.controller.valueController instanceof ListController$1) { - return new ListInputBindingApi$1(args.controller); - } - return null; - }, - }); - - const cn$d$1 = ClassName$1('col'); - class ColorView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$d$1()); - config.foldable.bindExpandedClass(this.element, cn$d$1(undefined, 'expanded')); - bindValueMap$1(config.foldable, 'completed', valueToClassName$1(this.element, cn$d$1(undefined, 'cpl'))); - const headElem = doc.createElement('div'); - headElem.classList.add(cn$d$1('h')); - this.element.appendChild(headElem); - const swatchElem = doc.createElement('div'); - swatchElem.classList.add(cn$d$1('s')); - headElem.appendChild(swatchElem); - this.swatchElement = swatchElem; - const textElem = doc.createElement('div'); - textElem.classList.add(cn$d$1('t')); - headElem.appendChild(textElem); - this.textElement = textElem; - if (config.pickerLayout === 'inline') { - const pickerElem = doc.createElement('div'); - pickerElem.classList.add(cn$d$1('p')); - this.element.appendChild(pickerElem); - this.pickerElement = pickerElem; - } - else { - this.pickerElement = null; - } - } - } - - function rgbToHslInt$1(r, g, b) { - const rp = constrainRange$1(r / 255, 0, 1); - const gp = constrainRange$1(g / 255, 0, 1); - const bp = constrainRange$1(b / 255, 0, 1); - const cmax = Math.max(rp, gp, bp); - const cmin = Math.min(rp, gp, bp); - const c = cmax - cmin; - let h = 0; - let s = 0; - const l = (cmin + cmax) / 2; - if (c !== 0) { - s = c / (1 - Math.abs(cmax + cmin - 1)); - if (rp === cmax) { - h = (gp - bp) / c; - } - else if (gp === cmax) { - h = 2 + (bp - rp) / c; - } - else { - h = 4 + (rp - gp) / c; - } - h = h / 6 + (h < 0 ? 1 : 0); - } - return [h * 360, s * 100, l * 100]; - } - function hslToRgbInt$1(h, s, l) { - const hp = ((h % 360) + 360) % 360; - const sp = constrainRange$1(s / 100, 0, 1); - const lp = constrainRange$1(l / 100, 0, 1); - const c = (1 - Math.abs(2 * lp - 1)) * sp; - const x = c * (1 - Math.abs(((hp / 60) % 2) - 1)); - const m = lp - c / 2; - let rp, gp, bp; - if (hp >= 0 && hp < 60) { - [rp, gp, bp] = [c, x, 0]; - } - else if (hp >= 60 && hp < 120) { - [rp, gp, bp] = [x, c, 0]; - } - else if (hp >= 120 && hp < 180) { - [rp, gp, bp] = [0, c, x]; - } - else if (hp >= 180 && hp < 240) { - [rp, gp, bp] = [0, x, c]; - } - else if (hp >= 240 && hp < 300) { - [rp, gp, bp] = [x, 0, c]; - } - else { - [rp, gp, bp] = [c, 0, x]; - } - return [(rp + m) * 255, (gp + m) * 255, (bp + m) * 255]; - } - function rgbToHsvInt$1(r, g, b) { - const rp = constrainRange$1(r / 255, 0, 1); - const gp = constrainRange$1(g / 255, 0, 1); - const bp = constrainRange$1(b / 255, 0, 1); - const cmax = Math.max(rp, gp, bp); - const cmin = Math.min(rp, gp, bp); - const d = cmax - cmin; - let h; - if (d === 0) { - h = 0; - } - else if (cmax === rp) { - h = 60 * (((((gp - bp) / d) % 6) + 6) % 6); - } - else if (cmax === gp) { - h = 60 * ((bp - rp) / d + 2); - } - else { - h = 60 * ((rp - gp) / d + 4); - } - const s = cmax === 0 ? 0 : d / cmax; - const v = cmax; - return [h, s * 100, v * 100]; - } - function hsvToRgbInt$1(h, s, v) { - const hp = loopRange$1(h, 360); - const sp = constrainRange$1(s / 100, 0, 1); - const vp = constrainRange$1(v / 100, 0, 1); - const c = vp * sp; - const x = c * (1 - Math.abs(((hp / 60) % 2) - 1)); - const m = vp - c; - let rp, gp, bp; - if (hp >= 0 && hp < 60) { - [rp, gp, bp] = [c, x, 0]; - } - else if (hp >= 60 && hp < 120) { - [rp, gp, bp] = [x, c, 0]; - } - else if (hp >= 120 && hp < 180) { - [rp, gp, bp] = [0, c, x]; - } - else if (hp >= 180 && hp < 240) { - [rp, gp, bp] = [0, x, c]; - } - else if (hp >= 240 && hp < 300) { - [rp, gp, bp] = [x, 0, c]; - } - else { - [rp, gp, bp] = [c, 0, x]; - } - return [(rp + m) * 255, (gp + m) * 255, (bp + m) * 255]; - } - function hslToHsvInt$1(h, s, l) { - const sd = l + (s * (100 - Math.abs(2 * l - 100))) / (2 * 100); - return [ - h, - sd !== 0 ? (s * (100 - Math.abs(2 * l - 100))) / sd : 0, - l + (s * (100 - Math.abs(2 * l - 100))) / (2 * 100), - ]; - } - function hsvToHslInt$1(h, s, v) { - const sd = 100 - Math.abs((v * (200 - s)) / 100 - 100); - return [h, sd !== 0 ? (s * v) / sd : 0, (v * (200 - s)) / (2 * 100)]; - } - function removeAlphaComponent$1(comps) { - return [comps[0], comps[1], comps[2]]; - } - function appendAlphaComponent$1(comps, alpha) { - return [comps[0], comps[1], comps[2], alpha]; - } - const MODE_CONVERTER_MAP$1 = { - hsl: { - hsl: (h, s, l) => [h, s, l], - hsv: hslToHsvInt$1, - rgb: hslToRgbInt$1, - }, - hsv: { - hsl: hsvToHslInt$1, - hsv: (h, s, v) => [h, s, v], - rgb: hsvToRgbInt$1, - }, - rgb: { - hsl: rgbToHslInt$1, - hsv: rgbToHsvInt$1, - rgb: (r, g, b) => [r, g, b], - }, - }; - function getColorMaxComponents$1(mode, type) { - return [ - type === 'float' ? 1 : mode === 'rgb' ? 255 : 360, - type === 'float' ? 1 : mode === 'rgb' ? 255 : 100, - type === 'float' ? 1 : mode === 'rgb' ? 255 : 100, - ]; - } - function loopHueRange$1(hue, max) { - return hue === max ? max : loopRange$1(hue, max); - } - function constrainColorComponents$1(components, mode, type) { - var _a; - const ms = getColorMaxComponents$1(mode, type); - return [ - mode === 'rgb' - ? constrainRange$1(components[0], 0, ms[0]) - : loopHueRange$1(components[0], ms[0]), - constrainRange$1(components[1], 0, ms[1]), - constrainRange$1(components[2], 0, ms[2]), - constrainRange$1((_a = components[3]) !== null && _a !== void 0 ? _a : 1, 0, 1), - ]; - } - function convertColorType$1(comps, mode, from, to) { - const fms = getColorMaxComponents$1(mode, from); - const tms = getColorMaxComponents$1(mode, to); - return comps.map((c, index) => (c / fms[index]) * tms[index]); - } - function convertColor$1(components, from, to) { - const intComps = convertColorType$1(components, from.mode, from.type, 'int'); - const result = MODE_CONVERTER_MAP$1[from.mode][to.mode](...intComps); - return convertColorType$1(result, to.mode, 'int', to.type); - } - - class IntColor$1 { - static black() { - return new IntColor$1([0, 0, 0], 'rgb'); - } - constructor(comps, mode) { - this.type = 'int'; - this.mode = mode; - this.comps_ = constrainColorComponents$1(comps, mode, this.type); - } - getComponents(opt_mode) { - return appendAlphaComponent$1(convertColor$1(removeAlphaComponent$1(this.comps_), { mode: this.mode, type: this.type }, { mode: opt_mode !== null && opt_mode !== void 0 ? opt_mode : this.mode, type: this.type }), this.comps_[3]); - } - toRgbaObject() { - const rgbComps = this.getComponents('rgb'); - return { - r: rgbComps[0], - g: rgbComps[1], - b: rgbComps[2], - a: rgbComps[3], - }; - } - } - - const cn$c$1 = ClassName$1('colp'); - class ColorPickerView$1 { - constructor(doc, config) { - this.alphaViews_ = null; - this.element = doc.createElement('div'); - this.element.classList.add(cn$c$1()); - config.viewProps.bindClassModifiers(this.element); - const hsvElem = doc.createElement('div'); - hsvElem.classList.add(cn$c$1('hsv')); - const svElem = doc.createElement('div'); - svElem.classList.add(cn$c$1('sv')); - this.svPaletteView_ = config.svPaletteView; - svElem.appendChild(this.svPaletteView_.element); - hsvElem.appendChild(svElem); - const hElem = doc.createElement('div'); - hElem.classList.add(cn$c$1('h')); - this.hPaletteView_ = config.hPaletteView; - hElem.appendChild(this.hPaletteView_.element); - hsvElem.appendChild(hElem); - this.element.appendChild(hsvElem); - const rgbElem = doc.createElement('div'); - rgbElem.classList.add(cn$c$1('rgb')); - this.textsView_ = config.textsView; - rgbElem.appendChild(this.textsView_.element); - this.element.appendChild(rgbElem); - if (config.alphaViews) { - this.alphaViews_ = { - palette: config.alphaViews.palette, - text: config.alphaViews.text, - }; - const aElem = doc.createElement('div'); - aElem.classList.add(cn$c$1('a')); - const apElem = doc.createElement('div'); - apElem.classList.add(cn$c$1('ap')); - apElem.appendChild(this.alphaViews_.palette.element); - aElem.appendChild(apElem); - const atElem = doc.createElement('div'); - atElem.classList.add(cn$c$1('at')); - atElem.appendChild(this.alphaViews_.text.element); - aElem.appendChild(atElem); - this.element.appendChild(aElem); - } - } - get allFocusableElements() { - const elems = [ - this.svPaletteView_.element, - this.hPaletteView_.element, - this.textsView_.modeSelectElement, - ...this.textsView_.inputViews.map((v) => v.inputElement), - ]; - if (this.alphaViews_) { - elems.push(this.alphaViews_.palette.element, this.alphaViews_.text.inputElement); - } - return elems; - } - } - - function parseColorType$1(value) { - return value === 'int' ? 'int' : value === 'float' ? 'float' : undefined; - } - function parseColorInputParams$1(params) { - return parseRecord$1(params, (p) => ({ - color: p.optional.object({ - alpha: p.optional.boolean, - type: p.optional.custom(parseColorType$1), - }), - expanded: p.optional.boolean, - picker: p.optional.custom(parsePickerLayout$1), - readonly: p.optional.constant(false), - })); - } - function getKeyScaleForColor$1(forAlpha) { - return forAlpha ? 0.1 : 1; - } - function extractColorType$1(params) { - var _a; - return (_a = params.color) === null || _a === void 0 ? void 0 : _a.type; - } - - class FloatColor$1 { - constructor(comps, mode) { - this.type = 'float'; - this.mode = mode; - this.comps_ = constrainColorComponents$1(comps, mode, this.type); - } - getComponents(opt_mode) { - return appendAlphaComponent$1(convertColor$1(removeAlphaComponent$1(this.comps_), { mode: this.mode, type: this.type }, { mode: opt_mode !== null && opt_mode !== void 0 ? opt_mode : this.mode, type: this.type }), this.comps_[3]); - } - toRgbaObject() { - const rgbComps = this.getComponents('rgb'); - return { - r: rgbComps[0], - g: rgbComps[1], - b: rgbComps[2], - a: rgbComps[3], - }; - } - } - - const TYPE_TO_CONSTRUCTOR_MAP$1 = { - int: (comps, mode) => new IntColor$1(comps, mode), - float: (comps, mode) => new FloatColor$1(comps, mode), - }; - function createColor$1(comps, mode, type) { - return TYPE_TO_CONSTRUCTOR_MAP$1[type](comps, mode); - } - function isFloatColor$1(c) { - return c.type === 'float'; - } - function isIntColor$1(c) { - return c.type === 'int'; - } - function convertFloatToInt$1(cf) { - const comps = cf.getComponents(); - const ms = getColorMaxComponents$1(cf.mode, 'int'); - return new IntColor$1([ - Math.round(mapRange$1(comps[0], 0, 1, 0, ms[0])), - Math.round(mapRange$1(comps[1], 0, 1, 0, ms[1])), - Math.round(mapRange$1(comps[2], 0, 1, 0, ms[2])), - comps[3], - ], cf.mode); - } - function convertIntToFloat$1(ci) { - const comps = ci.getComponents(); - const ms = getColorMaxComponents$1(ci.mode, 'int'); - return new FloatColor$1([ - mapRange$1(comps[0], 0, ms[0], 0, 1), - mapRange$1(comps[1], 0, ms[1], 0, 1), - mapRange$1(comps[2], 0, ms[2], 0, 1), - comps[3], - ], ci.mode); - } - function mapColorType$1(c, type) { - if (c.type === type) { - return c; - } - if (isIntColor$1(c) && type === 'float') { - return convertIntToFloat$1(c); - } - if (isFloatColor$1(c) && type === 'int') { - return convertFloatToInt$1(c); - } - throw TpError$1.shouldNeverHappen(); - } - - function equalsStringColorFormat$1(f1, f2) { - return (f1.alpha === f2.alpha && - f1.mode === f2.mode && - f1.notation === f2.notation && - f1.type === f2.type); - } - function parseCssNumberOrPercentage$1(text, max) { - const m = text.match(/^(.+)%$/); - if (!m) { - return Math.min(parseFloat(text), max); - } - return Math.min(parseFloat(m[1]) * 0.01 * max, max); - } - const ANGLE_TO_DEG_MAP$1 = { - deg: (angle) => angle, - grad: (angle) => (angle * 360) / 400, - rad: (angle) => (angle * 360) / (2 * Math.PI), - turn: (angle) => angle * 360, - }; - function parseCssNumberOrAngle$1(text) { - const m = text.match(/^([0-9.]+?)(deg|grad|rad|turn)$/); - if (!m) { - return parseFloat(text); - } - const angle = parseFloat(m[1]); - const unit = m[2]; - return ANGLE_TO_DEG_MAP$1[unit](angle); - } - function parseFunctionalRgbColorComponents$1(text) { - const m = text.match(/^rgb\(\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/); - if (!m) { - return null; - } - const comps = [ - parseCssNumberOrPercentage$1(m[1], 255), - parseCssNumberOrPercentage$1(m[2], 255), - parseCssNumberOrPercentage$1(m[3], 255), - ]; - if (isNaN(comps[0]) || isNaN(comps[1]) || isNaN(comps[2])) { - return null; - } - return comps; - } - function parseFunctionalRgbColor$1(text) { - const comps = parseFunctionalRgbColorComponents$1(text); - return comps ? new IntColor$1(comps, 'rgb') : null; - } - function parseFunctionalRgbaColorComponents$1(text) { - const m = text.match(/^rgba\(\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/); - if (!m) { - return null; - } - const comps = [ - parseCssNumberOrPercentage$1(m[1], 255), - parseCssNumberOrPercentage$1(m[2], 255), - parseCssNumberOrPercentage$1(m[3], 255), - parseCssNumberOrPercentage$1(m[4], 1), - ]; - if (isNaN(comps[0]) || - isNaN(comps[1]) || - isNaN(comps[2]) || - isNaN(comps[3])) { - return null; - } - return comps; - } - function parseFunctionalRgbaColor$1(text) { - const comps = parseFunctionalRgbaColorComponents$1(text); - return comps ? new IntColor$1(comps, 'rgb') : null; - } - function parseFunctionalHslColorComponents$1(text) { - const m = text.match(/^hsl\(\s*([0-9A-Fa-f.]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/); - if (!m) { - return null; - } - const comps = [ - parseCssNumberOrAngle$1(m[1]), - parseCssNumberOrPercentage$1(m[2], 100), - parseCssNumberOrPercentage$1(m[3], 100), - ]; - if (isNaN(comps[0]) || isNaN(comps[1]) || isNaN(comps[2])) { - return null; - } - return comps; - } - function parseFunctionalHslColor$1(text) { - const comps = parseFunctionalHslColorComponents$1(text); - return comps ? new IntColor$1(comps, 'hsl') : null; - } - function parseHslaColorComponents$1(text) { - const m = text.match(/^hsla\(\s*([0-9A-Fa-f.]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/); - if (!m) { - return null; - } - const comps = [ - parseCssNumberOrAngle$1(m[1]), - parseCssNumberOrPercentage$1(m[2], 100), - parseCssNumberOrPercentage$1(m[3], 100), - parseCssNumberOrPercentage$1(m[4], 1), - ]; - if (isNaN(comps[0]) || - isNaN(comps[1]) || - isNaN(comps[2]) || - isNaN(comps[3])) { - return null; - } - return comps; - } - function parseFunctionalHslaColor$1(text) { - const comps = parseHslaColorComponents$1(text); - return comps ? new IntColor$1(comps, 'hsl') : null; - } - function parseHexRgbColorComponents$1(text) { - const mRgb = text.match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/); - if (mRgb) { - return [ - parseInt(mRgb[1] + mRgb[1], 16), - parseInt(mRgb[2] + mRgb[2], 16), - parseInt(mRgb[3] + mRgb[3], 16), - ]; - } - const mRrggbb = text.match(/^(?:#|0x)([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/); - if (mRrggbb) { - return [ - parseInt(mRrggbb[1], 16), - parseInt(mRrggbb[2], 16), - parseInt(mRrggbb[3], 16), - ]; - } - return null; - } - function parseHexRgbColor$1(text) { - const comps = parseHexRgbColorComponents$1(text); - return comps ? new IntColor$1(comps, 'rgb') : null; - } - function parseHexRgbaColorComponents$1(text) { - const mRgb = text.match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/); - if (mRgb) { - return [ - parseInt(mRgb[1] + mRgb[1], 16), - parseInt(mRgb[2] + mRgb[2], 16), - parseInt(mRgb[3] + mRgb[3], 16), - mapRange$1(parseInt(mRgb[4] + mRgb[4], 16), 0, 255, 0, 1), - ]; - } - const mRrggbb = text.match(/^(?:#|0x)?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/); - if (mRrggbb) { - return [ - parseInt(mRrggbb[1], 16), - parseInt(mRrggbb[2], 16), - parseInt(mRrggbb[3], 16), - mapRange$1(parseInt(mRrggbb[4], 16), 0, 255, 0, 1), - ]; - } - return null; - } - function parseHexRgbaColor$1(text) { - const comps = parseHexRgbaColorComponents$1(text); - return comps ? new IntColor$1(comps, 'rgb') : null; - } - function parseObjectRgbColorComponents$1(text) { - const m = text.match(/^\{\s*r\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*g\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*b\s*:\s*([0-9A-Fa-f.]+%?)\s*\}$/); - if (!m) { - return null; - } - const comps = [ - parseFloat(m[1]), - parseFloat(m[2]), - parseFloat(m[3]), - ]; - if (isNaN(comps[0]) || isNaN(comps[1]) || isNaN(comps[2])) { - return null; - } - return comps; - } - function createObjectRgbColorParser$1(type) { - return (text) => { - const comps = parseObjectRgbColorComponents$1(text); - return comps ? createColor$1(comps, 'rgb', type) : null; - }; - } - function parseObjectRgbaColorComponents$1(text) { - const m = text.match(/^\{\s*r\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*g\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*b\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*a\s*:\s*([0-9A-Fa-f.]+%?)\s*\}$/); - if (!m) { - return null; - } - const comps = [ - parseFloat(m[1]), - parseFloat(m[2]), - parseFloat(m[3]), - parseFloat(m[4]), - ]; - if (isNaN(comps[0]) || - isNaN(comps[1]) || - isNaN(comps[2]) || - isNaN(comps[3])) { - return null; - } - return comps; - } - function createObjectRgbaColorParser$1(type) { - return (text) => { - const comps = parseObjectRgbaColorComponents$1(text); - return comps ? createColor$1(comps, 'rgb', type) : null; - }; - } - const PARSER_AND_RESULT$1 = [ - { - parser: parseHexRgbColorComponents$1, - result: { - alpha: false, - mode: 'rgb', - notation: 'hex', - }, - }, - { - parser: parseHexRgbaColorComponents$1, - result: { - alpha: true, - mode: 'rgb', - notation: 'hex', - }, - }, - { - parser: parseFunctionalRgbColorComponents$1, - result: { - alpha: false, - mode: 'rgb', - notation: 'func', - }, - }, - { - parser: parseFunctionalRgbaColorComponents$1, - result: { - alpha: true, - mode: 'rgb', - notation: 'func', - }, - }, - { - parser: parseFunctionalHslColorComponents$1, - result: { - alpha: false, - mode: 'hsl', - notation: 'func', - }, - }, - { - parser: parseHslaColorComponents$1, - result: { - alpha: true, - mode: 'hsl', - notation: 'func', - }, - }, - { - parser: parseObjectRgbColorComponents$1, - result: { - alpha: false, - mode: 'rgb', - notation: 'object', - }, - }, - { - parser: parseObjectRgbaColorComponents$1, - result: { - alpha: true, - mode: 'rgb', - notation: 'object', - }, - }, - ]; - function detectStringColor$1(text) { - return PARSER_AND_RESULT$1.reduce((prev, { parser, result: detection }) => { - if (prev) { - return prev; - } - return parser(text) ? detection : null; - }, null); - } - function detectStringColorFormat$1(text, type = 'int') { - const r = detectStringColor$1(text); - if (!r) { - return null; - } - if (r.notation === 'hex' && type !== 'float') { - return Object.assign(Object.assign({}, r), { type: 'int' }); - } - if (r.notation === 'func') { - return Object.assign(Object.assign({}, r), { type: type }); - } - return null; - } - function createColorStringParser$1(type) { - const parsers = [ - parseHexRgbColor$1, - parseHexRgbaColor$1, - parseFunctionalRgbColor$1, - parseFunctionalRgbaColor$1, - parseFunctionalHslColor$1, - parseFunctionalHslaColor$1, - ]; - if (type === 'int') { - parsers.push(createObjectRgbColorParser$1('int'), createObjectRgbaColorParser$1('int')); - } - if (type === 'float') { - parsers.push(createObjectRgbColorParser$1('float'), createObjectRgbaColorParser$1('float')); - } - const parser = composeParsers$1(parsers); - return (text) => { - const result = parser(text); - return result ? mapColorType$1(result, type) : null; - }; - } - function readIntColorString$1(value) { - const parser = createColorStringParser$1('int'); - if (typeof value !== 'string') { - return IntColor$1.black(); - } - const result = parser(value); - return result !== null && result !== void 0 ? result : IntColor$1.black(); - } - function zerofill$1(comp) { - const hex = constrainRange$1(Math.floor(comp), 0, 255).toString(16); - return hex.length === 1 ? `0${hex}` : hex; - } - function colorToHexRgbString$1(value, prefix = '#') { - const hexes = removeAlphaComponent$1(value.getComponents('rgb')) - .map(zerofill$1) - .join(''); - return `${prefix}${hexes}`; - } - function colorToHexRgbaString$1(value, prefix = '#') { - const rgbaComps = value.getComponents('rgb'); - const hexes = [rgbaComps[0], rgbaComps[1], rgbaComps[2], rgbaComps[3] * 255] - .map(zerofill$1) - .join(''); - return `${prefix}${hexes}`; - } - function colorToFunctionalRgbString$1(value) { - const formatter = createNumberFormatter$1(0); - const ci = mapColorType$1(value, 'int'); - const comps = removeAlphaComponent$1(ci.getComponents('rgb')).map((comp) => formatter(comp)); - return `rgb(${comps.join(', ')})`; - } - function colorToFunctionalRgbaString$1(value) { - const aFormatter = createNumberFormatter$1(2); - const rgbFormatter = createNumberFormatter$1(0); - const ci = mapColorType$1(value, 'int'); - const comps = ci.getComponents('rgb').map((comp, index) => { - const formatter = index === 3 ? aFormatter : rgbFormatter; - return formatter(comp); - }); - return `rgba(${comps.join(', ')})`; - } - function colorToFunctionalHslString$1(value) { - const formatters = [ - createNumberFormatter$1(0), - formatPercentage$1, - formatPercentage$1, - ]; - const ci = mapColorType$1(value, 'int'); - const comps = removeAlphaComponent$1(ci.getComponents('hsl')).map((comp, index) => formatters[index](comp)); - return `hsl(${comps.join(', ')})`; - } - function colorToFunctionalHslaString$1(value) { - const formatters = [ - createNumberFormatter$1(0), - formatPercentage$1, - formatPercentage$1, - createNumberFormatter$1(2), - ]; - const ci = mapColorType$1(value, 'int'); - const comps = ci - .getComponents('hsl') - .map((comp, index) => formatters[index](comp)); - return `hsla(${comps.join(', ')})`; - } - function colorToObjectRgbString$1(value, type) { - const formatter = createNumberFormatter$1(type === 'float' ? 2 : 0); - const names = ['r', 'g', 'b']; - const cc = mapColorType$1(value, type); - const comps = removeAlphaComponent$1(cc.getComponents('rgb')).map((comp, index) => `${names[index]}: ${formatter(comp)}`); - return `{${comps.join(', ')}}`; - } - function createObjectRgbColorFormatter$1(type) { - return (value) => colorToObjectRgbString$1(value, type); - } - function colorToObjectRgbaString$1(value, type) { - const aFormatter = createNumberFormatter$1(2); - const rgbFormatter = createNumberFormatter$1(type === 'float' ? 2 : 0); - const names = ['r', 'g', 'b', 'a']; - const cc = mapColorType$1(value, type); - const comps = cc.getComponents('rgb').map((comp, index) => { - const formatter = index === 3 ? aFormatter : rgbFormatter; - return `${names[index]}: ${formatter(comp)}`; - }); - return `{${comps.join(', ')}}`; - } - function createObjectRgbaColorFormatter$1(type) { - return (value) => colorToObjectRgbaString$1(value, type); - } - const FORMAT_AND_STRINGIFIERS$1 = [ - { - format: { - alpha: false, - mode: 'rgb', - notation: 'hex', - type: 'int', - }, - stringifier: colorToHexRgbString$1, - }, - { - format: { - alpha: true, - mode: 'rgb', - notation: 'hex', - type: 'int', - }, - stringifier: colorToHexRgbaString$1, - }, - { - format: { - alpha: false, - mode: 'rgb', - notation: 'func', - type: 'int', - }, - stringifier: colorToFunctionalRgbString$1, - }, - { - format: { - alpha: true, - mode: 'rgb', - notation: 'func', - type: 'int', - }, - stringifier: colorToFunctionalRgbaString$1, - }, - { - format: { - alpha: false, - mode: 'hsl', - notation: 'func', - type: 'int', - }, - stringifier: colorToFunctionalHslString$1, - }, - { - format: { - alpha: true, - mode: 'hsl', - notation: 'func', - type: 'int', - }, - stringifier: colorToFunctionalHslaString$1, - }, - ...['int', 'float'].reduce((prev, type) => { - return [ - ...prev, - { - format: { - alpha: false, - mode: 'rgb', - notation: 'object', - type: type, - }, - stringifier: createObjectRgbColorFormatter$1(type), - }, - { - format: { - alpha: true, - mode: 'rgb', - notation: 'object', - type: type, - }, - stringifier: createObjectRgbaColorFormatter$1(type), - }, - ]; - }, []), - ]; - function findColorStringifier$1(format) { - return FORMAT_AND_STRINGIFIERS$1.reduce((prev, fas) => { - if (prev) { - return prev; - } - return equalsStringColorFormat$1(fas.format, format) - ? fas.stringifier - : null; - }, null); - } - - const cn$b$1 = ClassName$1('apl'); - class APaletteView$1 { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.value = config.value; - this.value.emitter.on('change', this.onValueChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$b$1()); - config.viewProps.bindClassModifiers(this.element); - config.viewProps.bindTabIndex(this.element); - const barElem = doc.createElement('div'); - barElem.classList.add(cn$b$1('b')); - this.element.appendChild(barElem); - const colorElem = doc.createElement('div'); - colorElem.classList.add(cn$b$1('c')); - barElem.appendChild(colorElem); - this.colorElem_ = colorElem; - const markerElem = doc.createElement('div'); - markerElem.classList.add(cn$b$1('m')); - this.element.appendChild(markerElem); - this.markerElem_ = markerElem; - const previewElem = doc.createElement('div'); - previewElem.classList.add(cn$b$1('p')); - this.markerElem_.appendChild(previewElem); - this.previewElem_ = previewElem; - this.update_(); - } - update_() { - const c = this.value.rawValue; - const rgbaComps = c.getComponents('rgb'); - const leftColor = new IntColor$1([rgbaComps[0], rgbaComps[1], rgbaComps[2], 0], 'rgb'); - const rightColor = new IntColor$1([rgbaComps[0], rgbaComps[1], rgbaComps[2], 255], 'rgb'); - const gradientComps = [ - 'to right', - colorToFunctionalRgbaString$1(leftColor), - colorToFunctionalRgbaString$1(rightColor), - ]; - this.colorElem_.style.background = `linear-gradient(${gradientComps.join(',')})`; - this.previewElem_.style.backgroundColor = colorToFunctionalRgbaString$1(c); - const left = mapRange$1(rgbaComps[3], 0, 1, 0, 100); - this.markerElem_.style.left = `${left}%`; - } - onValueChange_() { - this.update_(); - } - } - - class APaletteController$1 { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new APaletteView$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler$1(this.view.element); - this.ptHandler_.emitter.on('down', this.onPointerDown_); - this.ptHandler_.emitter.on('move', this.onPointerMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.element.addEventListener('keydown', this.onKeyDown_); - this.view.element.addEventListener('keyup', this.onKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - const alpha = d.point.x / d.bounds.width; - const c = this.value.rawValue; - const [h, s, v] = c.getComponents('hsv'); - this.value.setRawValue(new IntColor$1([h, s, v, alpha], 'hsv'), opts); - } - onPointerDown_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - const step = getStepForKey$1(getKeyScaleForColor$1(true), getHorizontalStepKeys$1(ev)); - if (step === 0) { - return; - } - const c = this.value.rawValue; - const [h, s, v, a] = c.getComponents('hsv'); - this.value.setRawValue(new IntColor$1([h, s, v, a + step], 'hsv'), { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - const step = getStepForKey$1(getKeyScaleForColor$1(true), getHorizontalStepKeys$1(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - const cn$a$1 = ClassName$1('coltxt'); - function createModeSelectElement$1(doc) { - const selectElem = doc.createElement('select'); - const items = [ - { text: 'RGB', value: 'rgb' }, - { text: 'HSL', value: 'hsl' }, - { text: 'HSV', value: 'hsv' }, - { text: 'HEX', value: 'hex' }, - ]; - selectElem.appendChild(items.reduce((frag, item) => { - const optElem = doc.createElement('option'); - optElem.textContent = item.text; - optElem.value = item.value; - frag.appendChild(optElem); - return frag; - }, doc.createDocumentFragment())); - return selectElem; - } - class ColorTextsView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$a$1()); - config.viewProps.bindClassModifiers(this.element); - const modeElem = doc.createElement('div'); - modeElem.classList.add(cn$a$1('m')); - this.modeElem_ = createModeSelectElement$1(doc); - this.modeElem_.classList.add(cn$a$1('ms')); - modeElem.appendChild(this.modeSelectElement); - config.viewProps.bindDisabled(this.modeElem_); - const modeMarkerElem = doc.createElement('div'); - modeMarkerElem.classList.add(cn$a$1('mm')); - modeMarkerElem.appendChild(createSvgIconElement$1(doc, 'dropdown')); - modeElem.appendChild(modeMarkerElem); - this.element.appendChild(modeElem); - const inputsElem = doc.createElement('div'); - inputsElem.classList.add(cn$a$1('w')); - this.element.appendChild(inputsElem); - this.inputsElem_ = inputsElem; - this.inputViews_ = config.inputViews; - this.applyInputViews_(); - bindValue$1(config.mode, (mode) => { - this.modeElem_.value = mode; - }); - } - get modeSelectElement() { - return this.modeElem_; - } - get inputViews() { - return this.inputViews_; - } - set inputViews(inputViews) { - this.inputViews_ = inputViews; - this.applyInputViews_(); - } - applyInputViews_() { - removeChildElements$1(this.inputsElem_); - const doc = this.element.ownerDocument; - this.inputViews_.forEach((v) => { - const compElem = doc.createElement('div'); - compElem.classList.add(cn$a$1('c')); - compElem.appendChild(v.element); - this.inputsElem_.appendChild(compElem); - }); - } - } - - function createFormatter$2$1(type) { - return createNumberFormatter$1(type === 'float' ? 2 : 0); - } - function createConstraint$5$1(mode, type, index) { - const max = getColorMaxComponents$1(mode, type)[index]; - return new DefiniteRangeConstraint$1({ - min: 0, - max: max, - }); - } - function createComponentController$1(doc, config, index) { - return new NumberTextController$1(doc, { - arrayPosition: index === 0 ? 'fst' : index === 3 - 1 ? 'lst' : 'mid', - parser: config.parser, - props: ValueMap$1.fromObject({ - formatter: createFormatter$2$1(config.colorType), - keyScale: getKeyScaleForColor$1(false), - pointerScale: config.colorType === 'float' ? 0.01 : 1, - }), - value: createValue$1(0, { - constraint: createConstraint$5$1(config.colorMode, config.colorType, index), - }), - viewProps: config.viewProps, - }); - } - function createComponentControllers$1(doc, config) { - const cc = { - colorMode: config.colorMode, - colorType: config.colorType, - parser: parseNumber$1, - viewProps: config.viewProps, - }; - return [0, 1, 2].map((i) => { - const c = createComponentController$1(doc, cc, i); - connectValues$1({ - primary: config.value, - secondary: c.value, - forward(p) { - const mc = mapColorType$1(p, config.colorType); - return mc.getComponents(config.colorMode)[i]; - }, - backward(p, s) { - const pickedMode = config.colorMode; - const mc = mapColorType$1(p, config.colorType); - const comps = mc.getComponents(pickedMode); - comps[i] = s; - const c = createColor$1(appendAlphaComponent$1(removeAlphaComponent$1(comps), comps[3]), pickedMode, config.colorType); - return mapColorType$1(c, 'int'); - }, - }); - return c; - }); - } - function createHexController$1(doc, config) { - const c = new TextController$1(doc, { - parser: createColorStringParser$1('int'), - props: ValueMap$1.fromObject({ - formatter: colorToHexRgbString$1, - }), - value: createValue$1(IntColor$1.black()), - viewProps: config.viewProps, - }); - connectValues$1({ - primary: config.value, - secondary: c.value, - forward: (p) => new IntColor$1(removeAlphaComponent$1(p.getComponents()), p.mode), - backward: (p, s) => new IntColor$1(appendAlphaComponent$1(removeAlphaComponent$1(s.getComponents(p.mode)), p.getComponents()[3]), p.mode), - }); - return [c]; - } - function isColorMode$1(mode) { - return mode !== 'hex'; - } - class ColorTextsController$1 { - constructor(doc, config) { - this.onModeSelectChange_ = this.onModeSelectChange_.bind(this); - this.colorType_ = config.colorType; - this.value = config.value; - this.viewProps = config.viewProps; - this.colorMode = createValue$1(this.value.rawValue.mode); - this.ccs_ = this.createComponentControllers_(doc); - this.view = new ColorTextsView$1(doc, { - mode: this.colorMode, - inputViews: [this.ccs_[0].view, this.ccs_[1].view, this.ccs_[2].view], - viewProps: this.viewProps, - }); - this.view.modeSelectElement.addEventListener('change', this.onModeSelectChange_); - } - createComponentControllers_(doc) { - const mode = this.colorMode.rawValue; - if (isColorMode$1(mode)) { - return createComponentControllers$1(doc, { - colorMode: mode, - colorType: this.colorType_, - value: this.value, - viewProps: this.viewProps, - }); - } - return createHexController$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - } - onModeSelectChange_(ev) { - const selectElem = ev.currentTarget; - this.colorMode.rawValue = selectElem.value; - this.ccs_ = this.createComponentControllers_(this.view.element.ownerDocument); - this.view.inputViews = this.ccs_.map((cc) => cc.view); - } - } - - const cn$9$1 = ClassName$1('hpl'); - class HPaletteView$1 { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.value = config.value; - this.value.emitter.on('change', this.onValueChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$9$1()); - config.viewProps.bindClassModifiers(this.element); - config.viewProps.bindTabIndex(this.element); - const colorElem = doc.createElement('div'); - colorElem.classList.add(cn$9$1('c')); - this.element.appendChild(colorElem); - const markerElem = doc.createElement('div'); - markerElem.classList.add(cn$9$1('m')); - this.element.appendChild(markerElem); - this.markerElem_ = markerElem; - this.update_(); - } - update_() { - const c = this.value.rawValue; - const [h] = c.getComponents('hsv'); - this.markerElem_.style.backgroundColor = colorToFunctionalRgbString$1(new IntColor$1([h, 100, 100], 'hsv')); - const left = mapRange$1(h, 0, 360, 0, 100); - this.markerElem_.style.left = `${left}%`; - } - onValueChange_() { - this.update_(); - } - } - - class HPaletteController$1 { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new HPaletteView$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler$1(this.view.element); - this.ptHandler_.emitter.on('down', this.onPointerDown_); - this.ptHandler_.emitter.on('move', this.onPointerMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.element.addEventListener('keydown', this.onKeyDown_); - this.view.element.addEventListener('keyup', this.onKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - const hue = mapRange$1(constrainRange$1(d.point.x, 0, d.bounds.width), 0, d.bounds.width, 0, 360); - const c = this.value.rawValue; - const [, s, v, a] = c.getComponents('hsv'); - this.value.setRawValue(new IntColor$1([hue, s, v, a], 'hsv'), opts); - } - onPointerDown_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - const step = getStepForKey$1(getKeyScaleForColor$1(false), getHorizontalStepKeys$1(ev)); - if (step === 0) { - return; - } - const c = this.value.rawValue; - const [h, s, v, a] = c.getComponents('hsv'); - this.value.setRawValue(new IntColor$1([h + step, s, v, a], 'hsv'), { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - const step = getStepForKey$1(getKeyScaleForColor$1(false), getHorizontalStepKeys$1(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - const cn$8$1 = ClassName$1('svp'); - const CANVAS_RESOL$1 = 64; - class SvPaletteView$1 { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.value = config.value; - this.value.emitter.on('change', this.onValueChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$8$1()); - config.viewProps.bindClassModifiers(this.element); - config.viewProps.bindTabIndex(this.element); - const canvasElem = doc.createElement('canvas'); - canvasElem.height = CANVAS_RESOL$1; - canvasElem.width = CANVAS_RESOL$1; - canvasElem.classList.add(cn$8$1('c')); - this.element.appendChild(canvasElem); - this.canvasElement = canvasElem; - const markerElem = doc.createElement('div'); - markerElem.classList.add(cn$8$1('m')); - this.element.appendChild(markerElem); - this.markerElem_ = markerElem; - this.update_(); - } - update_() { - const ctx = getCanvasContext$1(this.canvasElement); - if (!ctx) { - return; - } - const c = this.value.rawValue; - const hsvComps = c.getComponents('hsv'); - const width = this.canvasElement.width; - const height = this.canvasElement.height; - const imgData = ctx.getImageData(0, 0, width, height); - const data = imgData.data; - for (let iy = 0; iy < height; iy++) { - for (let ix = 0; ix < width; ix++) { - const s = mapRange$1(ix, 0, width, 0, 100); - const v = mapRange$1(iy, 0, height, 100, 0); - const rgbComps = hsvToRgbInt$1(hsvComps[0], s, v); - const i = (iy * width + ix) * 4; - data[i] = rgbComps[0]; - data[i + 1] = rgbComps[1]; - data[i + 2] = rgbComps[2]; - data[i + 3] = 255; - } - } - ctx.putImageData(imgData, 0, 0); - const left = mapRange$1(hsvComps[1], 0, 100, 0, 100); - this.markerElem_.style.left = `${left}%`; - const top = mapRange$1(hsvComps[2], 0, 100, 100, 0); - this.markerElem_.style.top = `${top}%`; - } - onValueChange_() { - this.update_(); - } - } - - class SvPaletteController$1 { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new SvPaletteView$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler$1(this.view.element); - this.ptHandler_.emitter.on('down', this.onPointerDown_); - this.ptHandler_.emitter.on('move', this.onPointerMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.element.addEventListener('keydown', this.onKeyDown_); - this.view.element.addEventListener('keyup', this.onKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - const saturation = mapRange$1(d.point.x, 0, d.bounds.width, 0, 100); - const value = mapRange$1(d.point.y, 0, d.bounds.height, 100, 0); - const [h, , , a] = this.value.rawValue.getComponents('hsv'); - this.value.setRawValue(new IntColor$1([h, saturation, value, a], 'hsv'), opts); - } - onPointerDown_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - if (isArrowKey$1(ev.key)) { - ev.preventDefault(); - } - const [h, s, v, a] = this.value.rawValue.getComponents('hsv'); - const keyScale = getKeyScaleForColor$1(false); - const ds = getStepForKey$1(keyScale, getHorizontalStepKeys$1(ev)); - const dv = getStepForKey$1(keyScale, getVerticalStepKeys$1(ev)); - if (ds === 0 && dv === 0) { - return; - } - this.value.setRawValue(new IntColor$1([h, s + ds, v + dv, a], 'hsv'), { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - const keyScale = getKeyScaleForColor$1(false); - const ds = getStepForKey$1(keyScale, getHorizontalStepKeys$1(ev)); - const dv = getStepForKey$1(keyScale, getVerticalStepKeys$1(ev)); - if (ds === 0 && dv === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - class ColorPickerController$1 { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.hPaletteC_ = new HPaletteController$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.svPaletteC_ = new SvPaletteController$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.alphaIcs_ = config.supportsAlpha - ? { - palette: new APaletteController$1(doc, { - value: this.value, - viewProps: this.viewProps, - }), - text: new NumberTextController$1(doc, { - parser: parseNumber$1, - props: ValueMap$1.fromObject({ - pointerScale: 0.01, - keyScale: 0.1, - formatter: createNumberFormatter$1(2), - }), - value: createValue$1(0, { - constraint: new DefiniteRangeConstraint$1({ min: 0, max: 1 }), - }), - viewProps: this.viewProps, - }), - } - : null; - if (this.alphaIcs_) { - connectValues$1({ - primary: this.value, - secondary: this.alphaIcs_.text.value, - forward: (p) => p.getComponents()[3], - backward: (p, s) => { - const comps = p.getComponents(); - comps[3] = s; - return new IntColor$1(comps, p.mode); - }, - }); - } - this.textsC_ = new ColorTextsController$1(doc, { - colorType: config.colorType, - value: this.value, - viewProps: this.viewProps, - }); - this.view = new ColorPickerView$1(doc, { - alphaViews: this.alphaIcs_ - ? { - palette: this.alphaIcs_.palette.view, - text: this.alphaIcs_.text.view, - } - : null, - hPaletteView: this.hPaletteC_.view, - supportsAlpha: config.supportsAlpha, - svPaletteView: this.svPaletteC_.view, - textsView: this.textsC_.view, - viewProps: this.viewProps, - }); - } - get textsController() { - return this.textsC_; - } - } - - const cn$7$1 = ClassName$1('colsw'); - class ColorSwatchView$1 { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - config.value.emitter.on('change', this.onValueChange_); - this.value = config.value; - this.element = doc.createElement('div'); - this.element.classList.add(cn$7$1()); - config.viewProps.bindClassModifiers(this.element); - const swatchElem = doc.createElement('div'); - swatchElem.classList.add(cn$7$1('sw')); - this.element.appendChild(swatchElem); - this.swatchElem_ = swatchElem; - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(cn$7$1('b')); - config.viewProps.bindDisabled(buttonElem); - this.element.appendChild(buttonElem); - this.buttonElement = buttonElem; - this.update_(); - } - update_() { - const value = this.value.rawValue; - this.swatchElem_.style.backgroundColor = colorToHexRgbaString$1(value); - } - onValueChange_() { - this.update_(); - } - } - - class ColorSwatchController$1 { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new ColorSwatchView$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - } - } - - class ColorController$1 { - constructor(doc, config) { - this.onButtonBlur_ = this.onButtonBlur_.bind(this); - this.onButtonClick_ = this.onButtonClick_.bind(this); - this.onPopupChildBlur_ = this.onPopupChildBlur_.bind(this); - this.onPopupChildKeydown_ = this.onPopupChildKeydown_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.foldable_ = Foldable$1.create(config.expanded); - this.swatchC_ = new ColorSwatchController$1(doc, { - value: this.value, - viewProps: this.viewProps, - }); - const buttonElem = this.swatchC_.view.buttonElement; - buttonElem.addEventListener('blur', this.onButtonBlur_); - buttonElem.addEventListener('click', this.onButtonClick_); - this.textC_ = new TextController$1(doc, { - parser: config.parser, - props: ValueMap$1.fromObject({ - formatter: config.formatter, - }), - value: this.value, - viewProps: this.viewProps, - }); - this.view = new ColorView$1(doc, { - foldable: this.foldable_, - pickerLayout: config.pickerLayout, - }); - this.view.swatchElement.appendChild(this.swatchC_.view.element); - this.view.textElement.appendChild(this.textC_.view.element); - this.popC_ = - config.pickerLayout === 'popup' - ? new PopupController$1(doc, { - viewProps: this.viewProps, - }) - : null; - const pickerC = new ColorPickerController$1(doc, { - colorType: config.colorType, - supportsAlpha: config.supportsAlpha, - value: this.value, - viewProps: this.viewProps, - }); - pickerC.view.allFocusableElements.forEach((elem) => { - elem.addEventListener('blur', this.onPopupChildBlur_); - elem.addEventListener('keydown', this.onPopupChildKeydown_); - }); - this.pickerC_ = pickerC; - if (this.popC_) { - this.view.element.appendChild(this.popC_.view.element); - this.popC_.view.element.appendChild(pickerC.view.element); - connectValues$1({ - primary: this.foldable_.value('expanded'), - secondary: this.popC_.shows, - forward: (p) => p, - backward: (_, s) => s, - }); - } - else if (this.view.pickerElement) { - this.view.pickerElement.appendChild(this.pickerC_.view.element); - bindFoldable$1(this.foldable_, this.view.pickerElement); - } - } - get textController() { - return this.textC_; - } - onButtonBlur_(e) { - if (!this.popC_) { - return; - } - const elem = this.view.element; - const nextTarget = forceCast$1(e.relatedTarget); - if (!nextTarget || !elem.contains(nextTarget)) { - this.popC_.shows.rawValue = false; - } - } - onButtonClick_() { - this.foldable_.set('expanded', !this.foldable_.get('expanded')); - if (this.foldable_.get('expanded')) { - this.pickerC_.view.allFocusableElements[0].focus(); - } - } - onPopupChildBlur_(ev) { - if (!this.popC_) { - return; - } - const elem = this.popC_.view.element; - const nextTarget = findNextTarget$1(ev); - if (nextTarget && elem.contains(nextTarget)) { - return; - } - if (nextTarget && - nextTarget === this.swatchC_.view.buttonElement && - !supportsTouch$1(elem.ownerDocument)) { - return; - } - this.popC_.shows.rawValue = false; - } - onPopupChildKeydown_(ev) { - if (this.popC_) { - if (ev.key === 'Escape') { - this.popC_.shows.rawValue = false; - } - } - else if (this.view.pickerElement) { - if (ev.key === 'Escape') { - this.swatchC_.view.buttonElement.focus(); - } - } - } - } - - function colorToRgbNumber$1(value) { - return removeAlphaComponent$1(value.getComponents('rgb')).reduce((result, comp) => { - return (result << 8) | (Math.floor(comp) & 0xff); - }, 0); - } - function colorToRgbaNumber$1(value) { - return (value.getComponents('rgb').reduce((result, comp, index) => { - const hex = Math.floor(index === 3 ? comp * 255 : comp) & 0xff; - return (result << 8) | hex; - }, 0) >>> 0); - } - function numberToRgbColor$1(num) { - return new IntColor$1([(num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff], 'rgb'); - } - function numberToRgbaColor$1(num) { - return new IntColor$1([ - (num >> 24) & 0xff, - (num >> 16) & 0xff, - (num >> 8) & 0xff, - mapRange$1(num & 0xff, 0, 255, 0, 1), - ], 'rgb'); - } - function colorFromRgbNumber$1(value) { - if (typeof value !== 'number') { - return IntColor$1.black(); - } - return numberToRgbColor$1(value); - } - function colorFromRgbaNumber$1(value) { - if (typeof value !== 'number') { - return IntColor$1.black(); - } - return numberToRgbaColor$1(value); - } - - function isRgbColorComponent$1(obj, key) { - if (typeof obj !== 'object' || isEmpty$1(obj)) { - return false; - } - return key in obj && typeof obj[key] === 'number'; - } - function isRgbColorObject$1(obj) { - return (isRgbColorComponent$1(obj, 'r') && - isRgbColorComponent$1(obj, 'g') && - isRgbColorComponent$1(obj, 'b')); - } - function isRgbaColorObject$1(obj) { - return isRgbColorObject$1(obj) && isRgbColorComponent$1(obj, 'a'); - } - function isColorObject$1(obj) { - return isRgbColorObject$1(obj); - } - function equalsColor$1(v1, v2) { - if (v1.mode !== v2.mode) { - return false; - } - if (v1.type !== v2.type) { - return false; - } - const comps1 = v1.getComponents(); - const comps2 = v2.getComponents(); - for (let i = 0; i < comps1.length; i++) { - if (comps1[i] !== comps2[i]) { - return false; - } - } - return true; - } - function createColorComponentsFromRgbObject$1(obj) { - return 'a' in obj ? [obj.r, obj.g, obj.b, obj.a] : [obj.r, obj.g, obj.b]; - } - - function createColorStringWriter$1(format) { - const stringify = findColorStringifier$1(format); - return stringify - ? (target, value) => { - writePrimitive$1(target, stringify(value)); - } - : null; - } - function createColorNumberWriter$1(supportsAlpha) { - const colorToNumber = supportsAlpha ? colorToRgbaNumber$1 : colorToRgbNumber$1; - return (target, value) => { - writePrimitive$1(target, colorToNumber(value)); - }; - } - function writeRgbaColorObject$1(target, value, type) { - const cc = mapColorType$1(value, type); - const obj = cc.toRgbaObject(); - target.writeProperty('r', obj.r); - target.writeProperty('g', obj.g); - target.writeProperty('b', obj.b); - target.writeProperty('a', obj.a); - } - function writeRgbColorObject$1(target, value, type) { - const cc = mapColorType$1(value, type); - const obj = cc.toRgbaObject(); - target.writeProperty('r', obj.r); - target.writeProperty('g', obj.g); - target.writeProperty('b', obj.b); - } - function createColorObjectWriter$1(supportsAlpha, type) { - return (target, inValue) => { - if (supportsAlpha) { - writeRgbaColorObject$1(target, inValue, type); - } - else { - writeRgbColorObject$1(target, inValue, type); - } - }; - } - - function shouldSupportAlpha$1$1(inputParams) { - var _a; - if ((_a = inputParams === null || inputParams === void 0 ? void 0 : inputParams.color) === null || _a === void 0 ? void 0 : _a.alpha) { - return true; - } - return false; - } - function createFormatter$1$1(supportsAlpha) { - return supportsAlpha - ? (v) => colorToHexRgbaString$1(v, '0x') - : (v) => colorToHexRgbString$1(v, '0x'); - } - function isForColor$1(params) { - if ('color' in params) { - return true; - } - if (params.view === 'color') { - return true; - } - return false; - } - const NumberColorInputPlugin = createPlugin$1({ - id: 'input-color-number', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'number') { - return null; - } - if (!isForColor$1(params)) { - return null; - } - const result = parseColorInputParams$1(params); - return result - ? { - initialValue: value, - params: Object.assign(Object.assign({}, result), { supportsAlpha: shouldSupportAlpha$1$1(params) }), - } - : null; - }, - binding: { - reader: (args) => { - return args.params.supportsAlpha - ? colorFromRgbaNumber$1 - : colorFromRgbNumber$1; - }, - equals: equalsColor$1, - writer: (args) => { - return createColorNumberWriter$1(args.params.supportsAlpha); - }, - }, - controller: (args) => { - var _a, _b; - return new ColorController$1(args.document, { - colorType: 'int', - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - formatter: createFormatter$1$1(args.params.supportsAlpha), - parser: createColorStringParser$1('int'), - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - supportsAlpha: args.params.supportsAlpha, - value: args.value, - viewProps: args.viewProps, - }); - }, - }); - - function colorFromObject$1(value, type) { - if (!isColorObject$1(value)) { - return mapColorType$1(IntColor$1.black(), type); - } - if (type === 'int') { - const comps = createColorComponentsFromRgbObject$1(value); - return new IntColor$1(comps, 'rgb'); - } - if (type === 'float') { - const comps = createColorComponentsFromRgbObject$1(value); - return new FloatColor$1(comps, 'rgb'); - } - return mapColorType$1(IntColor$1.black(), 'int'); - } - - function shouldSupportAlpha$2(initialValue) { - return isRgbaColorObject$1(initialValue); - } - function createColorObjectBindingReader$1(type) { - return (value) => { - const c = colorFromObject$1(value, type); - return mapColorType$1(c, 'int'); - }; - } - function createColorObjectFormatter$1(supportsAlpha, type) { - return (value) => { - if (supportsAlpha) { - return colorToObjectRgbaString$1(value, type); - } - return colorToObjectRgbString$1(value, type); - }; - } - const ObjectColorInputPlugin = createPlugin$1({ - id: 'input-color-object', - type: 'input', - accept: (value, params) => { - var _a; - if (!isColorObject$1(value)) { - return null; - } - const result = parseColorInputParams$1(params); - return result - ? { - initialValue: value, - params: Object.assign(Object.assign({}, result), { colorType: (_a = extractColorType$1(params)) !== null && _a !== void 0 ? _a : 'int' }), - } - : null; - }, - binding: { - reader: (args) => createColorObjectBindingReader$1(args.params.colorType), - equals: equalsColor$1, - writer: (args) => createColorObjectWriter$1(shouldSupportAlpha$2(args.initialValue), args.params.colorType), - }, - controller: (args) => { - var _a, _b; - const supportsAlpha = isRgbaColorObject$1(args.initialValue); - return new ColorController$1(args.document, { - colorType: args.params.colorType, - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - formatter: createColorObjectFormatter$1(supportsAlpha, args.params.colorType), - parser: createColorStringParser$1('int'), - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - supportsAlpha: supportsAlpha, - value: args.value, - viewProps: args.viewProps, - }); - }, - }); - - const StringColorInputPlugin = createPlugin$1({ - id: 'input-color-string', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'string') { - return null; - } - if (params.view === 'text') { - return null; - } - const format = detectStringColorFormat$1(value, extractColorType$1(params)); - if (!format) { - return null; - } - const stringifier = findColorStringifier$1(format); - if (!stringifier) { - return null; - } - const result = parseColorInputParams$1(params); - return result - ? { - initialValue: value, - params: Object.assign(Object.assign({}, result), { format: format, stringifier: stringifier }), - } - : null; - }, - binding: { - reader: () => readIntColorString$1, - equals: equalsColor$1, - writer: (args) => { - const writer = createColorStringWriter$1(args.params.format); - if (!writer) { - throw TpError$1.notBindable(); - } - return writer; - }, - }, - controller: (args) => { - var _a, _b; - return new ColorController$1(args.document, { - colorType: args.params.format.type, - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - formatter: args.params.stringifier, - parser: createColorStringParser$1('int'), - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - supportsAlpha: args.params.format.alpha, - value: args.value, - viewProps: args.viewProps, - }); - }, - }); - - class PointNdConstraint$1 { - constructor(config) { - this.components = config.components; - this.asm_ = config.assembly; - } - constrain(value) { - const comps = this.asm_ - .toComponents(value) - .map((comp, index) => { var _a, _b; return (_b = (_a = this.components[index]) === null || _a === void 0 ? void 0 : _a.constrain(comp)) !== null && _b !== void 0 ? _b : comp; }); - return this.asm_.fromComponents(comps); - } - } - - const cn$6$1 = ClassName$1('pndtxt'); - class PointNdTextView$1 { - constructor(doc, config) { - this.textViews = config.textViews; - this.element = doc.createElement('div'); - this.element.classList.add(cn$6$1()); - this.textViews.forEach((v) => { - const axisElem = doc.createElement('div'); - axisElem.classList.add(cn$6$1('a')); - axisElem.appendChild(v.element); - this.element.appendChild(axisElem); - }); - } - } - - function createAxisController$1(doc, config, index) { - return new NumberTextController$1(doc, { - arrayPosition: index === 0 ? 'fst' : index === config.axes.length - 1 ? 'lst' : 'mid', - parser: config.parser, - props: config.axes[index].textProps, - value: createValue$1(0, { - constraint: config.axes[index].constraint, - }), - viewProps: config.viewProps, - }); - } - class PointNdTextController$1 { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.acs_ = config.axes.map((_, index) => createAxisController$1(doc, config, index)); - this.acs_.forEach((c, index) => { - connectValues$1({ - primary: this.value, - secondary: c.value, - forward: (p) => config.assembly.toComponents(p)[index], - backward: (p, s) => { - const comps = config.assembly.toComponents(p); - comps[index] = s; - return config.assembly.fromComponents(comps); - }, - }); - }); - this.view = new PointNdTextView$1(doc, { - textViews: this.acs_.map((ac) => ac.view), - }); - } - get textControllers() { - return this.acs_; - } - } - - class SliderInputBindingApi$1 extends BindingApi$1 { - get max() { - return this.controller.valueController.sliderController.props.get('max'); - } - set max(max) { - this.controller.valueController.sliderController.props.set('max', max); - } - get min() { - return this.controller.valueController.sliderController.props.get('min'); - } - set min(max) { - this.controller.valueController.sliderController.props.set('min', max); - } - } - - function createConstraint$4$1(params, initialValue) { - const constraints = []; - const sc = createStepConstraint$1(params, initialValue); - if (sc) { - constraints.push(sc); - } - const rc = createRangeConstraint$1(params); - if (rc) { - constraints.push(rc); - } - const lc = createListConstraint$1(params.options); - if (lc) { - constraints.push(lc); - } - return new CompositeConstraint$1(constraints); - } - const NumberInputPlugin = createPlugin$1({ - id: 'input-number', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'number') { - return null; - } - const result = parseRecord$1(params, (p) => (Object.assign(Object.assign({}, createNumberTextInputParamsParser$1(p)), { options: p.optional.custom(parseListOptions$1), readonly: p.optional.constant(false) }))); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => numberFromUnknown$1, - constraint: (args) => createConstraint$4$1(args.params, args.initialValue), - writer: (_args) => writePrimitive$1, - }, - controller: (args) => { - const value = args.value; - const c = args.constraint; - const lc = c && findConstraint$1(c, ListConstraint$1); - if (lc) { - return new ListController$1(args.document, { - props: new ValueMap$1({ - options: lc.values.value('options'), - }), - value: value, - viewProps: args.viewProps, - }); - } - const textPropsObj = createNumberTextPropsObject$1(args.params, value.rawValue); - const drc = c && findConstraint$1(c, DefiniteRangeConstraint$1); - if (drc) { - return new SliderTextController$1(args.document, Object.assign(Object.assign({}, createSliderTextProps$1(Object.assign(Object.assign({}, textPropsObj), { keyScale: createValue$1(textPropsObj.keyScale), max: drc.values.value('max'), min: drc.values.value('min') }))), { parser: parseNumber$1, value: value, viewProps: args.viewProps })); - } - return new NumberTextController$1(args.document, { - parser: parseNumber$1, - props: ValueMap$1.fromObject(textPropsObj), - value: value, - viewProps: args.viewProps, - }); - }, - api(args) { - if (typeof args.controller.value.rawValue !== 'number') { - return null; - } - if (args.controller.valueController instanceof SliderTextController$1) { - return new SliderInputBindingApi$1(args.controller); - } - if (args.controller.valueController instanceof ListController$1) { - return new ListInputBindingApi$1(args.controller); - } - return null; - }, - }); - - class Point2d$1 { - constructor(x = 0, y = 0) { - this.x = x; - this.y = y; - } - getComponents() { - return [this.x, this.y]; - } - static isObject(obj) { - if (isEmpty$1(obj)) { - return false; - } - const x = obj.x; - const y = obj.y; - if (typeof x !== 'number' || typeof y !== 'number') { - return false; - } - return true; - } - static equals(v1, v2) { - return v1.x === v2.x && v1.y === v2.y; - } - toObject() { - return { - x: this.x, - y: this.y, - }; - } - } - const Point2dAssembly$1 = { - toComponents: (p) => p.getComponents(), - fromComponents: (comps) => new Point2d$1(...comps), - }; - - const cn$5$1 = ClassName$1('p2d'); - class Point2dView$1 { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$5$1()); - config.viewProps.bindClassModifiers(this.element); - bindValue$1(config.expanded, valueToClassName$1(this.element, cn$5$1(undefined, 'expanded'))); - const headElem = doc.createElement('div'); - headElem.classList.add(cn$5$1('h')); - this.element.appendChild(headElem); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(cn$5$1('b')); - buttonElem.appendChild(createSvgIconElement$1(doc, 'p2dpad')); - config.viewProps.bindDisabled(buttonElem); - headElem.appendChild(buttonElem); - this.buttonElement = buttonElem; - const textElem = doc.createElement('div'); - textElem.classList.add(cn$5$1('t')); - headElem.appendChild(textElem); - this.textElement = textElem; - if (config.pickerLayout === 'inline') { - const pickerElem = doc.createElement('div'); - pickerElem.classList.add(cn$5$1('p')); - this.element.appendChild(pickerElem); - this.pickerElement = pickerElem; - } - else { - this.pickerElement = null; - } - } - } - - const cn$4$1 = ClassName$1('p2dp'); - class Point2dPickerView$1 { - constructor(doc, config) { - this.onFoldableChange_ = this.onFoldableChange_.bind(this); - this.onPropsChange_ = this.onPropsChange_.bind(this); - this.onValueChange_ = this.onValueChange_.bind(this); - this.props_ = config.props; - this.props_.emitter.on('change', this.onPropsChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$4$1()); - if (config.layout === 'popup') { - this.element.classList.add(cn$4$1(undefined, 'p')); - } - config.viewProps.bindClassModifiers(this.element); - const padElem = doc.createElement('div'); - padElem.classList.add(cn$4$1('p')); - config.viewProps.bindTabIndex(padElem); - this.element.appendChild(padElem); - this.padElement = padElem; - const svgElem = doc.createElementNS(SVG_NS$1, 'svg'); - svgElem.classList.add(cn$4$1('g')); - this.padElement.appendChild(svgElem); - this.svgElem_ = svgElem; - const xAxisElem = doc.createElementNS(SVG_NS$1, 'line'); - xAxisElem.classList.add(cn$4$1('ax')); - xAxisElem.setAttributeNS(null, 'x1', '0'); - xAxisElem.setAttributeNS(null, 'y1', '50%'); - xAxisElem.setAttributeNS(null, 'x2', '100%'); - xAxisElem.setAttributeNS(null, 'y2', '50%'); - this.svgElem_.appendChild(xAxisElem); - const yAxisElem = doc.createElementNS(SVG_NS$1, 'line'); - yAxisElem.classList.add(cn$4$1('ax')); - yAxisElem.setAttributeNS(null, 'x1', '50%'); - yAxisElem.setAttributeNS(null, 'y1', '0'); - yAxisElem.setAttributeNS(null, 'x2', '50%'); - yAxisElem.setAttributeNS(null, 'y2', '100%'); - this.svgElem_.appendChild(yAxisElem); - const lineElem = doc.createElementNS(SVG_NS$1, 'line'); - lineElem.classList.add(cn$4$1('l')); - lineElem.setAttributeNS(null, 'x1', '50%'); - lineElem.setAttributeNS(null, 'y1', '50%'); - this.svgElem_.appendChild(lineElem); - this.lineElem_ = lineElem; - const markerElem = doc.createElement('div'); - markerElem.classList.add(cn$4$1('m')); - this.padElement.appendChild(markerElem); - this.markerElem_ = markerElem; - config.value.emitter.on('change', this.onValueChange_); - this.value = config.value; - this.update_(); - } - get allFocusableElements() { - return [this.padElement]; - } - update_() { - const [x, y] = this.value.rawValue.getComponents(); - const max = this.props_.get('max'); - const px = mapRange$1(x, -max, +max, 0, 100); - const py = mapRange$1(y, -max, +max, 0, 100); - const ipy = this.props_.get('invertsY') ? 100 - py : py; - this.lineElem_.setAttributeNS(null, 'x2', `${px}%`); - this.lineElem_.setAttributeNS(null, 'y2', `${ipy}%`); - this.markerElem_.style.left = `${px}%`; - this.markerElem_.style.top = `${ipy}%`; - } - onValueChange_() { - this.update_(); - } - onPropsChange_() { - this.update_(); - } - onFoldableChange_() { - this.update_(); - } - } - - function computeOffset$2(ev, keyScales, invertsY) { - return [ - getStepForKey$1(keyScales[0], getHorizontalStepKeys$1(ev)), - getStepForKey$1(keyScales[1], getVerticalStepKeys$1(ev)) * (invertsY ? 1 : -1), - ]; - } - class Point2dPickerController$1 { - constructor(doc, config) { - this.onPadKeyDown_ = this.onPadKeyDown_.bind(this); - this.onPadKeyUp_ = this.onPadKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.props = config.props; - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new Point2dPickerView$1(doc, { - layout: config.layout, - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler$1(this.view.padElement); - this.ptHandler_.emitter.on('down', this.onPointerDown_); - this.ptHandler_.emitter.on('move', this.onPointerMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.padElement.addEventListener('keydown', this.onPadKeyDown_); - this.view.padElement.addEventListener('keyup', this.onPadKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - const max = this.props.get('max'); - const px = mapRange$1(d.point.x, 0, d.bounds.width, -max, +max); - const py = mapRange$1(this.props.get('invertsY') ? d.bounds.height - d.point.y : d.point.y, 0, d.bounds.height, -max, +max); - this.value.setRawValue(new Point2d$1(px, py), opts); - } - onPointerDown_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onPadKeyDown_(ev) { - if (isArrowKey$1(ev.key)) { - ev.preventDefault(); - } - const [dx, dy] = computeOffset$2(ev, [this.props.get('xKeyScale'), this.props.get('yKeyScale')], this.props.get('invertsY')); - if (dx === 0 && dy === 0) { - return; - } - this.value.setRawValue(new Point2d$1(this.value.rawValue.x + dx, this.value.rawValue.y + dy), { - forceEmit: false, - last: false, - }); - } - onPadKeyUp_(ev) { - const [dx, dy] = computeOffset$2(ev, [this.props.get('xKeyScale'), this.props.get('yKeyScale')], this.props.get('invertsY')); - if (dx === 0 && dy === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - class Point2dController$1 { - constructor(doc, config) { - var _a, _b; - this.onPopupChildBlur_ = this.onPopupChildBlur_.bind(this); - this.onPopupChildKeydown_ = this.onPopupChildKeydown_.bind(this); - this.onPadButtonBlur_ = this.onPadButtonBlur_.bind(this); - this.onPadButtonClick_ = this.onPadButtonClick_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.foldable_ = Foldable$1.create(config.expanded); - this.popC_ = - config.pickerLayout === 'popup' - ? new PopupController$1(doc, { - viewProps: this.viewProps, - }) - : null; - const padC = new Point2dPickerController$1(doc, { - layout: config.pickerLayout, - props: new ValueMap$1({ - invertsY: createValue$1(config.invertsY), - max: createValue$1(config.max), - xKeyScale: config.axes[0].textProps.value('keyScale'), - yKeyScale: config.axes[1].textProps.value('keyScale'), - }), - value: this.value, - viewProps: this.viewProps, - }); - padC.view.allFocusableElements.forEach((elem) => { - elem.addEventListener('blur', this.onPopupChildBlur_); - elem.addEventListener('keydown', this.onPopupChildKeydown_); - }); - this.pickerC_ = padC; - this.textC_ = new PointNdTextController$1(doc, { - assembly: Point2dAssembly$1, - axes: config.axes, - parser: config.parser, - value: this.value, - viewProps: this.viewProps, - }); - this.view = new Point2dView$1(doc, { - expanded: this.foldable_.value('expanded'), - pickerLayout: config.pickerLayout, - viewProps: this.viewProps, - }); - this.view.textElement.appendChild(this.textC_.view.element); - (_a = this.view.buttonElement) === null || _a === void 0 ? void 0 : _a.addEventListener('blur', this.onPadButtonBlur_); - (_b = this.view.buttonElement) === null || _b === void 0 ? void 0 : _b.addEventListener('click', this.onPadButtonClick_); - if (this.popC_) { - this.view.element.appendChild(this.popC_.view.element); - this.popC_.view.element.appendChild(this.pickerC_.view.element); - connectValues$1({ - primary: this.foldable_.value('expanded'), - secondary: this.popC_.shows, - forward: (p) => p, - backward: (_, s) => s, - }); - } - else if (this.view.pickerElement) { - this.view.pickerElement.appendChild(this.pickerC_.view.element); - bindFoldable$1(this.foldable_, this.view.pickerElement); - } - } - get textController() { - return this.textC_; - } - onPadButtonBlur_(e) { - if (!this.popC_) { - return; - } - const elem = this.view.element; - const nextTarget = forceCast$1(e.relatedTarget); - if (!nextTarget || !elem.contains(nextTarget)) { - this.popC_.shows.rawValue = false; - } - } - onPadButtonClick_() { - this.foldable_.set('expanded', !this.foldable_.get('expanded')); - if (this.foldable_.get('expanded')) { - this.pickerC_.view.allFocusableElements[0].focus(); - } - } - onPopupChildBlur_(ev) { - if (!this.popC_) { - return; - } - const elem = this.popC_.view.element; - const nextTarget = findNextTarget$1(ev); - if (nextTarget && elem.contains(nextTarget)) { - return; - } - if (nextTarget && - nextTarget === this.view.buttonElement && - !supportsTouch$1(elem.ownerDocument)) { - return; - } - this.popC_.shows.rawValue = false; - } - onPopupChildKeydown_(ev) { - if (this.popC_) { - if (ev.key === 'Escape') { - this.popC_.shows.rawValue = false; - } - } - else if (this.view.pickerElement) { - if (ev.key === 'Escape') { - this.view.buttonElement.focus(); - } - } - } - } - - function point2dFromUnknown$1(value) { - return Point2d$1.isObject(value) - ? new Point2d$1(value.x, value.y) - : new Point2d$1(); - } - function writePoint2d$1(target, value) { - target.writeProperty('x', value.x); - target.writeProperty('y', value.y); - } - - function createConstraint$3$1(params, initialValue) { - return new PointNdConstraint$1({ - assembly: Point2dAssembly$1, - components: [ - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.x), initialValue.x), - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.y), initialValue.y), - ], - }); - } - function getSuitableMaxDimensionValue$1(params, rawValue) { - var _a, _b; - if (!isEmpty$1(params.min) || !isEmpty$1(params.max)) { - return Math.max(Math.abs((_a = params.min) !== null && _a !== void 0 ? _a : 0), Math.abs((_b = params.max) !== null && _b !== void 0 ? _b : 0)); - } - const step = getSuitableKeyScale$1(params); - return Math.max(Math.abs(step) * 10, Math.abs(rawValue) * 10); - } - function getSuitableMax$1(params, initialValue) { - var _a, _b; - const xr = getSuitableMaxDimensionValue$1(deepMerge$1(params, ((_a = params.x) !== null && _a !== void 0 ? _a : {})), initialValue.x); - const yr = getSuitableMaxDimensionValue$1(deepMerge$1(params, ((_b = params.y) !== null && _b !== void 0 ? _b : {})), initialValue.y); - return Math.max(xr, yr); - } - function shouldInvertY$1(params) { - if (!('y' in params)) { - return false; - } - const yParams = params.y; - if (!yParams) { - return false; - } - return 'inverted' in yParams ? !!yParams.inverted : false; - } - const Point2dInputPlugin = createPlugin$1({ - id: 'input-point2d', - type: 'input', - accept: (value, params) => { - if (!Point2d$1.isObject(value)) { - return null; - } - const result = parseRecord$1(params, (p) => (Object.assign(Object.assign({}, createPointDimensionParser$1(p)), { expanded: p.optional.boolean, picker: p.optional.custom(parsePickerLayout$1), readonly: p.optional.constant(false), x: p.optional.custom(parsePointDimensionParams$1), y: p.optional.object(Object.assign(Object.assign({}, createPointDimensionParser$1(p)), { inverted: p.optional.boolean })) }))); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: () => point2dFromUnknown$1, - constraint: (args) => createConstraint$3$1(args.params, args.initialValue), - equals: Point2d$1.equals, - writer: () => writePoint2d$1, - }, - controller: (args) => { - var _a, _b; - const doc = args.document; - const value = args.value; - const c = args.constraint; - const dParams = [args.params.x, args.params.y]; - return new Point2dController$1(doc, { - axes: value.rawValue.getComponents().map((comp, i) => { - var _a; - return createPointAxis$1({ - constraint: c.components[i], - initialValue: comp, - params: deepMerge$1(args.params, ((_a = dParams[i]) !== null && _a !== void 0 ? _a : {})), - }); - }), - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - invertsY: shouldInvertY$1(args.params), - max: getSuitableMax$1(args.params, value.rawValue), - parser: parseNumber$1, - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - value: value, - viewProps: args.viewProps, - }); - }, - }); - - class Point3d$1 { - constructor(x = 0, y = 0, z = 0) { - this.x = x; - this.y = y; - this.z = z; - } - getComponents() { - return [this.x, this.y, this.z]; - } - static isObject(obj) { - if (isEmpty$1(obj)) { - return false; - } - const x = obj.x; - const y = obj.y; - const z = obj.z; - if (typeof x !== 'number' || - typeof y !== 'number' || - typeof z !== 'number') { - return false; - } - return true; - } - static equals(v1, v2) { - return v1.x === v2.x && v1.y === v2.y && v1.z === v2.z; - } - toObject() { - return { - x: this.x, - y: this.y, - z: this.z, - }; - } - } - const Point3dAssembly$1 = { - toComponents: (p) => p.getComponents(), - fromComponents: (comps) => new Point3d$1(...comps), - }; - - function point3dFromUnknown$1(value) { - return Point3d$1.isObject(value) - ? new Point3d$1(value.x, value.y, value.z) - : new Point3d$1(); - } - function writePoint3d$1(target, value) { - target.writeProperty('x', value.x); - target.writeProperty('y', value.y); - target.writeProperty('z', value.z); - } - - function createConstraint$2$1(params, initialValue) { - return new PointNdConstraint$1({ - assembly: Point3dAssembly$1, - components: [ - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.x), initialValue.x), - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.y), initialValue.y), - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.z), initialValue.z), - ], - }); - } - const Point3dInputPlugin = createPlugin$1({ - id: 'input-point3d', - type: 'input', - accept: (value, params) => { - if (!Point3d$1.isObject(value)) { - return null; - } - const result = parseRecord$1(params, (p) => (Object.assign(Object.assign({}, createPointDimensionParser$1(p)), { readonly: p.optional.constant(false), x: p.optional.custom(parsePointDimensionParams$1), y: p.optional.custom(parsePointDimensionParams$1), z: p.optional.custom(parsePointDimensionParams$1) }))); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => point3dFromUnknown$1, - constraint: (args) => createConstraint$2$1(args.params, args.initialValue), - equals: Point3d$1.equals, - writer: (_args) => writePoint3d$1, - }, - controller: (args) => { - const value = args.value; - const c = args.constraint; - const dParams = [args.params.x, args.params.y, args.params.z]; - return new PointNdTextController$1(args.document, { - assembly: Point3dAssembly$1, - axes: value.rawValue.getComponents().map((comp, i) => { - var _a; - return createPointAxis$1({ - constraint: c.components[i], - initialValue: comp, - params: deepMerge$1(args.params, ((_a = dParams[i]) !== null && _a !== void 0 ? _a : {})), - }); - }), - parser: parseNumber$1, - value: value, - viewProps: args.viewProps, - }); - }, - }); - - class Point4d$1 { - constructor(x = 0, y = 0, z = 0, w = 0) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - getComponents() { - return [this.x, this.y, this.z, this.w]; - } - static isObject(obj) { - if (isEmpty$1(obj)) { - return false; - } - const x = obj.x; - const y = obj.y; - const z = obj.z; - const w = obj.w; - if (typeof x !== 'number' || - typeof y !== 'number' || - typeof z !== 'number' || - typeof w !== 'number') { - return false; - } - return true; - } - static equals(v1, v2) { - return v1.x === v2.x && v1.y === v2.y && v1.z === v2.z && v1.w === v2.w; - } - toObject() { - return { - x: this.x, - y: this.y, - z: this.z, - w: this.w, - }; - } - } - const Point4dAssembly$1 = { - toComponents: (p) => p.getComponents(), - fromComponents: (comps) => new Point4d$1(...comps), - }; - - function point4dFromUnknown$1(value) { - return Point4d$1.isObject(value) - ? new Point4d$1(value.x, value.y, value.z, value.w) - : new Point4d$1(); - } - function writePoint4d$1(target, value) { - target.writeProperty('x', value.x); - target.writeProperty('y', value.y); - target.writeProperty('z', value.z); - target.writeProperty('w', value.w); - } - - function createConstraint$1$1(params, initialValue) { - return new PointNdConstraint$1({ - assembly: Point4dAssembly$1, - components: [ - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.x), initialValue.x), - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.y), initialValue.y), - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.z), initialValue.z), - createDimensionConstraint$1(Object.assign(Object.assign({}, params), params.w), initialValue.w), - ], - }); - } - const Point4dInputPlugin = createPlugin$1({ - id: 'input-point4d', - type: 'input', - accept: (value, params) => { - if (!Point4d$1.isObject(value)) { - return null; - } - const result = parseRecord$1(params, (p) => (Object.assign(Object.assign({}, createPointDimensionParser$1(p)), { readonly: p.optional.constant(false), w: p.optional.custom(parsePointDimensionParams$1), x: p.optional.custom(parsePointDimensionParams$1), y: p.optional.custom(parsePointDimensionParams$1), z: p.optional.custom(parsePointDimensionParams$1) }))); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => point4dFromUnknown$1, - constraint: (args) => createConstraint$1$1(args.params, args.initialValue), - equals: Point4d$1.equals, - writer: (_args) => writePoint4d$1, - }, - controller: (args) => { - const value = args.value; - const c = args.constraint; - const dParams = [ - args.params.x, - args.params.y, - args.params.z, - args.params.w, - ]; - return new PointNdTextController$1(args.document, { - assembly: Point4dAssembly$1, - axes: value.rawValue.getComponents().map((comp, i) => { - var _a; - return createPointAxis$1({ - constraint: c.components[i], - initialValue: comp, - params: deepMerge$1(args.params, ((_a = dParams[i]) !== null && _a !== void 0 ? _a : {})), - }); - }), - parser: parseNumber$1, - value: value, - viewProps: args.viewProps, - }); - }, - }); - - function createConstraint$9(params) { - const constraints = []; - const lc = createListConstraint$1(params.options); - if (lc) { - constraints.push(lc); - } - return new CompositeConstraint$1(constraints); - } - const StringInputPlugin = createPlugin$1({ - id: 'input-string', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'string') { - return null; - } - const result = parseRecord$1(params, (p) => ({ - readonly: p.optional.constant(false), - options: p.optional.custom(parseListOptions$1), - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => stringFromUnknown$1, - constraint: (args) => createConstraint$9(args.params), - writer: (_args) => writePrimitive$1, - }, - controller: (args) => { - const doc = args.document; - const value = args.value; - const c = args.constraint; - const lc = c && findConstraint$1(c, ListConstraint$1); - if (lc) { - return new ListController$1(doc, { - props: new ValueMap$1({ - options: lc.values.value('options'), - }), - value: value, - viewProps: args.viewProps, - }); - } - return new TextController$1(doc, { - parser: (v) => v, - props: ValueMap$1.fromObject({ - formatter: formatString$1, - }), - value: value, - viewProps: args.viewProps, - }); - }, - api(args) { - if (typeof args.controller.value.rawValue !== 'string') { - return null; - } - if (args.controller.valueController instanceof ListController$1) { - return new ListInputBindingApi$1(args.controller); - } - return null; - }, - }); - - const Constants$1 = { - monitor: { - defaultInterval: 200, - defaultRows: 3, - }, - }; - - const cn$3$1 = ClassName$1('mll'); - class MultiLogView$1 { - constructor(doc, config) { - this.onValueUpdate_ = this.onValueUpdate_.bind(this); - this.formatter_ = config.formatter; - this.element = doc.createElement('div'); - this.element.classList.add(cn$3$1()); - config.viewProps.bindClassModifiers(this.element); - const textareaElem = doc.createElement('textarea'); - textareaElem.classList.add(cn$3$1('i')); - textareaElem.style.height = `calc(var(${getCssVar$1('containerUnitSize')}) * ${config.rows})`; - textareaElem.readOnly = true; - config.viewProps.bindDisabled(textareaElem); - this.element.appendChild(textareaElem); - this.textareaElem_ = textareaElem; - config.value.emitter.on('change', this.onValueUpdate_); - this.value = config.value; - this.update_(); - } - update_() { - const elem = this.textareaElem_; - const shouldScroll = elem.scrollTop === elem.scrollHeight - elem.clientHeight; - const lines = []; - this.value.rawValue.forEach((value) => { - if (value !== undefined) { - lines.push(this.formatter_(value)); - } - }); - elem.textContent = lines.join('\n'); - if (shouldScroll) { - elem.scrollTop = elem.scrollHeight; - } - } - onValueUpdate_() { - this.update_(); - } - } - - class MultiLogController$1 { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new MultiLogView$1(doc, { - formatter: config.formatter, - rows: config.rows, - value: this.value, - viewProps: this.viewProps, - }); - } - } - - const cn$2$1 = ClassName$1('sgl'); - class SingleLogView$1 { - constructor(doc, config) { - this.onValueUpdate_ = this.onValueUpdate_.bind(this); - this.formatter_ = config.formatter; - this.element = doc.createElement('div'); - this.element.classList.add(cn$2$1()); - config.viewProps.bindClassModifiers(this.element); - const inputElem = doc.createElement('input'); - inputElem.classList.add(cn$2$1('i')); - inputElem.readOnly = true; - inputElem.type = 'text'; - config.viewProps.bindDisabled(inputElem); - this.element.appendChild(inputElem); - this.inputElement = inputElem; - config.value.emitter.on('change', this.onValueUpdate_); - this.value = config.value; - this.update_(); - } - update_() { - const values = this.value.rawValue; - const lastValue = values[values.length - 1]; - this.inputElement.value = - lastValue !== undefined ? this.formatter_(lastValue) : ''; - } - onValueUpdate_() { - this.update_(); - } - } - - class SingleLogController$1 { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new SingleLogView$1(doc, { - formatter: config.formatter, - value: this.value, - viewProps: this.viewProps, - }); - } - } - - const BooleanMonitorPlugin = createPlugin$1({ - id: 'monitor-bool', - type: 'monitor', - accept: (value, params) => { - if (typeof value !== 'boolean') { - return null; - } - const result = parseRecord$1(params, (p) => ({ - readonly: p.required.constant(true), - rows: p.optional.number, - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => boolFromUnknown$1, - }, - controller: (args) => { - var _a; - if (args.value.rawValue.length === 1) { - return new SingleLogController$1(args.document, { - formatter: BooleanFormatter$1, - value: args.value, - viewProps: args.viewProps, - }); - } - return new MultiLogController$1(args.document, { - formatter: BooleanFormatter$1, - rows: (_a = args.params.rows) !== null && _a !== void 0 ? _a : Constants$1.monitor.defaultRows, - value: args.value, - viewProps: args.viewProps, - }); - }, - }); - - class GraphLogMonitorBindingApi$1 extends BindingApi$1 { - get max() { - return this.controller.valueController.props.get('max'); - } - set max(max) { - this.controller.valueController.props.set('max', max); - } - get min() { - return this.controller.valueController.props.get('min'); - } - set min(min) { - this.controller.valueController.props.set('min', min); - } - } - - const cn$1$1 = ClassName$1('grl'); - class GraphLogView$1 { - constructor(doc, config) { - this.onCursorChange_ = this.onCursorChange_.bind(this); - this.onValueUpdate_ = this.onValueUpdate_.bind(this); - this.element = doc.createElement('div'); - this.element.classList.add(cn$1$1()); - config.viewProps.bindClassModifiers(this.element); - this.formatter_ = config.formatter; - this.props_ = config.props; - this.cursor_ = config.cursor; - this.cursor_.emitter.on('change', this.onCursorChange_); - const svgElem = doc.createElementNS(SVG_NS$1, 'svg'); - svgElem.classList.add(cn$1$1('g')); - svgElem.style.height = `calc(var(${getCssVar$1('containerUnitSize')}) * ${config.rows})`; - this.element.appendChild(svgElem); - this.svgElem_ = svgElem; - const lineElem = doc.createElementNS(SVG_NS$1, 'polyline'); - this.svgElem_.appendChild(lineElem); - this.lineElem_ = lineElem; - const tooltipElem = doc.createElement('div'); - tooltipElem.classList.add(cn$1$1('t'), ClassName$1('tt')()); - this.element.appendChild(tooltipElem); - this.tooltipElem_ = tooltipElem; - config.value.emitter.on('change', this.onValueUpdate_); - this.value = config.value; - this.update_(); - } - get graphElement() { - return this.svgElem_; - } - update_() { - const { clientWidth: w, clientHeight: h } = this.element; - const maxIndex = this.value.rawValue.length - 1; - const min = this.props_.get('min'); - const max = this.props_.get('max'); - const points = []; - this.value.rawValue.forEach((v, index) => { - if (v === undefined) { - return; - } - const x = mapRange$1(index, 0, maxIndex, 0, w); - const y = mapRange$1(v, min, max, h, 0); - points.push([x, y].join(',')); - }); - this.lineElem_.setAttributeNS(null, 'points', points.join(' ')); - const tooltipElem = this.tooltipElem_; - const value = this.value.rawValue[this.cursor_.rawValue]; - if (value === undefined) { - tooltipElem.classList.remove(cn$1$1('t', 'a')); - return; - } - const tx = mapRange$1(this.cursor_.rawValue, 0, maxIndex, 0, w); - const ty = mapRange$1(value, min, max, h, 0); - tooltipElem.style.left = `${tx}px`; - tooltipElem.style.top = `${ty}px`; - tooltipElem.textContent = `${this.formatter_(value)}`; - if (!tooltipElem.classList.contains(cn$1$1('t', 'a'))) { - tooltipElem.classList.add(cn$1$1('t', 'a'), cn$1$1('t', 'in')); - forceReflow$1(tooltipElem); - tooltipElem.classList.remove(cn$1$1('t', 'in')); - } - } - onValueUpdate_() { - this.update_(); - } - onCursorChange_() { - this.update_(); - } - } - - class GraphLogController$1 { - constructor(doc, config) { - this.onGraphMouseMove_ = this.onGraphMouseMove_.bind(this); - this.onGraphMouseLeave_ = this.onGraphMouseLeave_.bind(this); - this.onGraphPointerDown_ = this.onGraphPointerDown_.bind(this); - this.onGraphPointerMove_ = this.onGraphPointerMove_.bind(this); - this.onGraphPointerUp_ = this.onGraphPointerUp_.bind(this); - this.props = config.props; - this.value = config.value; - this.viewProps = config.viewProps; - this.cursor_ = createValue$1(-1); - this.view = new GraphLogView$1(doc, { - cursor: this.cursor_, - formatter: config.formatter, - rows: config.rows, - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - if (!supportsTouch$1(doc)) { - this.view.element.addEventListener('mousemove', this.onGraphMouseMove_); - this.view.element.addEventListener('mouseleave', this.onGraphMouseLeave_); - } - else { - const ph = new PointerHandler$1(this.view.element); - ph.emitter.on('down', this.onGraphPointerDown_); - ph.emitter.on('move', this.onGraphPointerMove_); - ph.emitter.on('up', this.onGraphPointerUp_); - } - } - importProps(state) { - return importBladeState$1(state, null, (p) => ({ - max: p.required.number, - min: p.required.number, - }), (result) => { - this.props.set('max', result.max); - this.props.set('min', result.min); - return true; - }); - } - exportProps() { - return exportBladeState$1(null, { - max: this.props.get('max'), - min: this.props.get('min'), - }); - } - onGraphMouseLeave_() { - this.cursor_.rawValue = -1; - } - onGraphMouseMove_(ev) { - const { clientWidth: w } = this.view.element; - this.cursor_.rawValue = Math.floor(mapRange$1(ev.offsetX, 0, w, 0, this.value.rawValue.length)); - } - onGraphPointerDown_(ev) { - this.onGraphPointerMove_(ev); - } - onGraphPointerMove_(ev) { - if (!ev.data.point) { - this.cursor_.rawValue = -1; - return; - } - this.cursor_.rawValue = Math.floor(mapRange$1(ev.data.point.x, 0, ev.data.bounds.width, 0, this.value.rawValue.length)); - } - onGraphPointerUp_() { - this.cursor_.rawValue = -1; - } - } - - function createFormatter$3(params) { - return !isEmpty$1(params.format) ? params.format : createNumberFormatter$1(2); - } - function createTextMonitor$1(args) { - var _a; - if (args.value.rawValue.length === 1) { - return new SingleLogController$1(args.document, { - formatter: createFormatter$3(args.params), - value: args.value, - viewProps: args.viewProps, - }); - } - return new MultiLogController$1(args.document, { - formatter: createFormatter$3(args.params), - rows: (_a = args.params.rows) !== null && _a !== void 0 ? _a : Constants$1.monitor.defaultRows, - value: args.value, - viewProps: args.viewProps, - }); - } - function createGraphMonitor$1(args) { - var _a, _b, _c; - return new GraphLogController$1(args.document, { - formatter: createFormatter$3(args.params), - rows: (_a = args.params.rows) !== null && _a !== void 0 ? _a : Constants$1.monitor.defaultRows, - props: ValueMap$1.fromObject({ - max: (_b = args.params.max) !== null && _b !== void 0 ? _b : 100, - min: (_c = args.params.min) !== null && _c !== void 0 ? _c : 0, - }), - value: args.value, - viewProps: args.viewProps, - }); - } - function shouldShowGraph$1(params) { - return params.view === 'graph'; - } - const NumberMonitorPlugin = createPlugin$1({ - id: 'monitor-number', - type: 'monitor', - accept: (value, params) => { - if (typeof value !== 'number') { - return null; - } - const result = parseRecord$1(params, (p) => ({ - format: p.optional.function, - max: p.optional.number, - min: p.optional.number, - readonly: p.required.constant(true), - rows: p.optional.number, - view: p.optional.string, - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - defaultBufferSize: (params) => (shouldShowGraph$1(params) ? 64 : 1), - reader: (_args) => numberFromUnknown$1, - }, - controller: (args) => { - if (shouldShowGraph$1(args.params)) { - return createGraphMonitor$1(args); - } - return createTextMonitor$1(args); - }, - api: (args) => { - if (args.controller.valueController instanceof GraphLogController$1) { - return new GraphLogMonitorBindingApi$1(args.controller); - } - return null; - }, - }); - - const StringMonitorPlugin = createPlugin$1({ - id: 'monitor-string', - type: 'monitor', - accept: (value, params) => { - if (typeof value !== 'string') { - return null; - } - const result = parseRecord$1(params, (p) => ({ - multiline: p.optional.boolean, - readonly: p.required.constant(true), - rows: p.optional.number, - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => stringFromUnknown$1, - }, - controller: (args) => { - var _a; - const value = args.value; - const multiline = value.rawValue.length > 1 || args.params.multiline; - if (multiline) { - return new MultiLogController$1(args.document, { - formatter: formatString$1, - rows: (_a = args.params.rows) !== null && _a !== void 0 ? _a : Constants$1.monitor.defaultRows, - value: value, - viewProps: args.viewProps, - }); - } - return new SingleLogController$1(args.document, { - formatter: formatString$1, - value: value, - viewProps: args.viewProps, - }); - }, - }); - - class BladeApiCache { - constructor() { - this.map_ = new Map(); - } - get(bc) { - var _a; - return (_a = this.map_.get(bc)) !== null && _a !== void 0 ? _a : null; - } - has(bc) { - return this.map_.has(bc); - } - add(bc, api) { - this.map_.set(bc, api); - bc.viewProps.handleDispose(() => { - this.map_.delete(bc); - }); - return api; - } - } - - class ReadWriteBinding { - constructor(config) { - this.target = config.target; - this.reader_ = config.reader; - this.writer_ = config.writer; - } - read() { - return this.reader_(this.target.read()); - } - write(value) { - this.writer_(this.target, value); - } - inject(value) { - this.write(this.reader_(value)); - } - } - - function createInputBindingController(plugin, args) { - var _a; - const result = plugin.accept(args.target.read(), args.params); - if (isEmpty$1(result)) { - return null; - } - const valueArgs = { - target: args.target, - initialValue: result.initialValue, - params: result.params, - }; - const params = parseRecord$1(args.params, (p) => ({ - disabled: p.optional.boolean, - hidden: p.optional.boolean, - label: p.optional.string, - tag: p.optional.string, - })); - const reader = plugin.binding.reader(valueArgs); - const constraint = plugin.binding.constraint - ? plugin.binding.constraint(valueArgs) - : undefined; - const binding = new ReadWriteBinding({ - reader: reader, - target: args.target, - writer: plugin.binding.writer(valueArgs), - }); - const value = new InputBindingValue(createValue$1(reader(result.initialValue), { - constraint: constraint, - equals: plugin.binding.equals, - }), binding); - const controller = plugin.controller({ - constraint: constraint, - document: args.document, - initialValue: result.initialValue, - params: result.params, - value: value, - viewProps: ViewProps$1.create({ - disabled: params === null || params === void 0 ? void 0 : params.disabled, - hidden: params === null || params === void 0 ? void 0 : params.hidden, - }), - }); - return new InputBindingController(args.document, { - blade: createBlade$1(), - props: ValueMap$1.fromObject({ - label: 'label' in args.params ? (_a = params === null || params === void 0 ? void 0 : params.label) !== null && _a !== void 0 ? _a : null : args.target.key, - }), - tag: params === null || params === void 0 ? void 0 : params.tag, - value: value, - valueController: controller, - }); - } - - class ReadonlyBinding { - constructor(config) { - this.target = config.target; - this.reader_ = config.reader; - } - read() { - return this.reader_(this.target.read()); - } - } - - function createTicker$1(document, interval) { - return interval === 0 - ? new ManualTicker$1() - : new IntervalTicker$1(document, interval !== null && interval !== void 0 ? interval : Constants$1.monitor.defaultInterval); - } - function createMonitorBindingController(plugin, args) { - var _a, _b, _c; - const result = plugin.accept(args.target.read(), args.params); - if (isEmpty$1(result)) { - return null; - } - const bindingArgs = { - target: args.target, - initialValue: result.initialValue, - params: result.params, - }; - const params = parseRecord$1(args.params, (p) => ({ - bufferSize: p.optional.number, - disabled: p.optional.boolean, - hidden: p.optional.boolean, - interval: p.optional.number, - label: p.optional.string, - })); - const reader = plugin.binding.reader(bindingArgs); - const bufferSize = (_b = (_a = params === null || params === void 0 ? void 0 : params.bufferSize) !== null && _a !== void 0 ? _a : (plugin.binding.defaultBufferSize && - plugin.binding.defaultBufferSize(result.params))) !== null && _b !== void 0 ? _b : 1; - const value = new MonitorBindingValue({ - binding: new ReadonlyBinding({ - reader: reader, - target: args.target, - }), - bufferSize: bufferSize, - ticker: createTicker$1(args.document, params === null || params === void 0 ? void 0 : params.interval), - }); - const controller = plugin.controller({ - document: args.document, - params: result.params, - value: value, - viewProps: ViewProps$1.create({ - disabled: params === null || params === void 0 ? void 0 : params.disabled, - hidden: params === null || params === void 0 ? void 0 : params.hidden, - }), - }); - controller.viewProps.bindDisabled(value.ticker); - controller.viewProps.handleDispose(() => { - value.ticker.dispose(); - }); - return new MonitorBindingController(args.document, { - blade: createBlade$1(), - props: ValueMap$1.fromObject({ - label: 'label' in args.params ? (_c = params === null || params === void 0 ? void 0 : params.label) !== null && _c !== void 0 ? _c : null : args.target.key, - }), - value: value, - valueController: controller, - }); - } - - class PluginPool { - constructor(apiCache) { - this.pluginsMap_ = { - blades: [], - inputs: [], - monitors: [], - }; - this.apiCache_ = apiCache; - } - getAll() { - return [ - ...this.pluginsMap_.blades, - ...this.pluginsMap_.inputs, - ...this.pluginsMap_.monitors, - ]; - } - register(bundleId, r) { - if (!isCompatible(r.core)) { - throw TpError$1.notCompatible(bundleId, r.id); - } - if (r.type === 'blade') { - this.pluginsMap_.blades.unshift(r); - } - else if (r.type === 'input') { - this.pluginsMap_.inputs.unshift(r); - } - else if (r.type === 'monitor') { - this.pluginsMap_.monitors.unshift(r); - } - } - createInput_(document, target, params) { - return this.pluginsMap_.inputs.reduce((result, plugin) => result !== null && result !== void 0 ? result : createInputBindingController(plugin, { - document: document, - target: target, - params: params, - }), null); - } - createMonitor_(document, target, params) { - return this.pluginsMap_.monitors.reduce((result, plugin) => result !== null && result !== void 0 ? result : createMonitorBindingController(plugin, { - document: document, - params: params, - target: target, - }), null); - } - createBinding(doc, target, params) { - const initialValue = target.read(); - if (isEmpty$1(initialValue)) { - throw new TpError$1({ - context: { - key: target.key, - }, - type: 'nomatchingcontroller', - }); - } - const ic = this.createInput_(doc, target, params); - if (ic) { - return ic; - } - const mc = this.createMonitor_(doc, target, params); - if (mc) { - return mc; - } - throw new TpError$1({ - context: { - key: target.key, - }, - type: 'nomatchingcontroller', - }); - } - createBlade(document, params) { - const bc = this.pluginsMap_.blades.reduce((result, plugin) => result !== null && result !== void 0 ? result : createBladeController(plugin, { - document: document, - params: params, - }), null); - if (!bc) { - throw new TpError$1({ - type: 'nomatchingview', - context: { - params: params, - }, - }); - } - return bc; - } - createInputBindingApi_(bc) { - const api = this.pluginsMap_.inputs.reduce((result, plugin) => { - var _a, _b; - if (result) { - return result; - } - return ((_b = (_a = plugin.api) === null || _a === void 0 ? void 0 : _a.call(plugin, { - controller: bc, - })) !== null && _b !== void 0 ? _b : null); - }, null); - return this.apiCache_.add(bc, api !== null && api !== void 0 ? api : new BindingApi$1(bc)); - } - createMonitorBindingApi_(bc) { - const api = this.pluginsMap_.monitors.reduce((result, plugin) => { - var _a, _b; - if (result) { - return result; - } - return ((_b = (_a = plugin.api) === null || _a === void 0 ? void 0 : _a.call(plugin, { - controller: bc, - })) !== null && _b !== void 0 ? _b : null); - }, null); - return this.apiCache_.add(bc, api !== null && api !== void 0 ? api : new BindingApi$1(bc)); - } - createBindingApi(bc) { - if (this.apiCache_.has(bc)) { - return this.apiCache_.get(bc); - } - if (isInputBindingController(bc)) { - return this.createInputBindingApi_(bc); - } - if (isMonitorBindingController(bc)) { - return this.createMonitorBindingApi_(bc); - } - throw TpError$1.shouldNeverHappen(); - } - createApi(bc) { - if (this.apiCache_.has(bc)) { - return this.apiCache_.get(bc); - } - if (isBindingController(bc)) { - return this.createBindingApi(bc); - } - const api = this.pluginsMap_.blades.reduce((result, plugin) => result !== null && result !== void 0 ? result : plugin.api({ - controller: bc, - pool: this, - }), null); - if (!api) { - throw TpError$1.shouldNeverHappen(); - } - return this.apiCache_.add(bc, api); - } - } - - const sharedCache = new BladeApiCache(); - function createDefaultPluginPool() { - const pool = new PluginPool(sharedCache); - [ - Point2dInputPlugin, - Point3dInputPlugin, - Point4dInputPlugin, - StringInputPlugin, - NumberInputPlugin, - StringColorInputPlugin, - ObjectColorInputPlugin, - NumberColorInputPlugin, - BooleanInputPlugin, - BooleanMonitorPlugin, - StringMonitorPlugin, - NumberMonitorPlugin, - ButtonBladePlugin, - FolderBladePlugin, - TabBladePlugin, - ].forEach((p) => { - pool.register('core', p); - }); - return pool; - } - - class ListBladeApi extends BladeApi$1 { - /** - * @hidden - */ - constructor(controller) { - super(controller); - this.emitter_ = new Emitter$1(); - this.controller.value.emitter.on('change', (ev) => { - this.emitter_.emit('change', new TpChangeEvent$1(this, ev.rawValue)); - }); - } - get label() { - return this.controller.labelController.props.get('label'); - } - set label(label) { - this.controller.labelController.props.set('label', label); - } - get options() { - return this.controller.valueController.props.get('options'); - } - set options(options) { - this.controller.valueController.props.set('options', options); - } - get value() { - return this.controller.value.rawValue; - } - set value(value) { - this.controller.value.rawValue = value; - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }, { - key: handler, - }); - return this; - } - off(eventName, handler) { - this.emitter_.off(eventName, handler); - return this; - } - } - - class SeparatorBladeApi extends BladeApi$1 { - } - - class SliderBladeApi extends BladeApi$1 { - /** - * @hidden - */ - constructor(controller) { - super(controller); - this.emitter_ = new Emitter$1(); - this.controller.value.emitter.on('change', (ev) => { - this.emitter_.emit('change', new TpChangeEvent$1(this, ev.rawValue)); - }); - } - get label() { - return this.controller.labelController.props.get('label'); - } - set label(label) { - this.controller.labelController.props.set('label', label); - } - get max() { - return this.controller.valueController.sliderController.props.get('max'); - } - set max(max) { - this.controller.valueController.sliderController.props.set('max', max); - } - get min() { - return this.controller.valueController.sliderController.props.get('min'); - } - set min(min) { - this.controller.valueController.sliderController.props.set('min', min); - } - get value() { - return this.controller.value.rawValue; - } - set value(value) { - this.controller.value.rawValue = value; - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }, { - key: handler, - }); - return this; - } - off(eventName, handler) { - this.emitter_.off(eventName, handler); - return this; - } - } - - class TextBladeApi extends BladeApi$1 { - /** - * @hidden - */ - constructor(controller) { - super(controller); - this.emitter_ = new Emitter$1(); - this.controller.value.emitter.on('change', (ev) => { - this.emitter_.emit('change', new TpChangeEvent$1(this, ev.rawValue)); - }); - } - get label() { - return this.controller.labelController.props.get('label'); - } - set label(label) { - this.controller.labelController.props.set('label', label); - } - get formatter() { - return this.controller.valueController.props.get('formatter'); - } - set formatter(formatter) { - this.controller.valueController.props.set('formatter', formatter); - } - get value() { - return this.controller.value.rawValue; - } - set value(value) { - this.controller.value.rawValue = value; - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }, { - key: handler, - }); - return this; - } - off(eventName, handler) { - this.emitter_.off(eventName, handler); - return this; - } - } - - const ListBladePlugin = (function () { - return { - id: 'list', - type: 'blade', - core: VERSION$1, - accept(params) { - const result = parseRecord$1(params, (p) => ({ - options: p.required.custom(parseListOptions$1), - value: p.required.raw, - view: p.required.constant('list'), - label: p.optional.string, - })); - return result ? { params: result } : null; - }, - controller(args) { - const lc = new ListConstraint$1(normalizeListOptions$1(args.params.options)); - const value = createValue$1(args.params.value, { - constraint: lc, - }); - const ic = new ListController$1(args.document, { - props: new ValueMap$1({ - options: lc.values.value('options'), - }), - value: value, - viewProps: args.viewProps, - }); - return new LabeledValueBladeController$1(args.document, { - blade: args.blade, - props: ValueMap$1.fromObject({ - label: args.params.label, - }), - value: value, - valueController: ic, - }); - }, - api(args) { - if (!(args.controller instanceof LabeledValueBladeController$1)) { - return null; - } - if (!(args.controller.valueController instanceof ListController$1)) { - return null; - } - return new ListBladeApi(args.controller); - }, - }; - })(); - - class RootApi extends FolderApi$1 { - /** - * @hidden - */ - constructor(controller, pool) { - super(controller, pool); - } - get element() { - return this.controller.view.element; - } - } - - /** - * @hidden - */ - class RootController extends FolderController$1 { - constructor(doc, config) { - super(doc, { - expanded: config.expanded, - blade: config.blade, - props: config.props, - root: true, - viewProps: config.viewProps, - }); - } - } - - const cn$s = ClassName$1('spr'); - /** - * @hidden - */ - class SeparatorView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$s()); - config.viewProps.bindClassModifiers(this.element); - const hrElem = doc.createElement('hr'); - hrElem.classList.add(cn$s('r')); - this.element.appendChild(hrElem); - } - } - - /** - * @hidden - */ - class SeparatorController extends BladeController$1 { - /** - * @hidden - */ - constructor(doc, config) { - super(Object.assign(Object.assign({}, config), { view: new SeparatorView(doc, { - viewProps: config.viewProps, - }) })); - } - } - - const SeparatorBladePlugin = { - id: 'separator', - type: 'blade', - core: VERSION$1, - accept(params) { - const result = parseRecord$1(params, (p) => ({ - view: p.required.constant('separator'), - })); - return result ? { params: result } : null; - }, - controller(args) { - return new SeparatorController(args.document, { - blade: args.blade, - viewProps: args.viewProps, - }); - }, - api(args) { - if (!(args.controller instanceof SeparatorController)) { - return null; - } - return new SeparatorBladeApi(args.controller); - }, - }; - - const SliderBladePlugin = { - id: 'slider', - type: 'blade', - core: VERSION$1, - accept(params) { - const result = parseRecord$1(params, (p) => ({ - max: p.required.number, - min: p.required.number, - view: p.required.constant('slider'), - format: p.optional.function, - label: p.optional.string, - value: p.optional.number, - })); - return result ? { params: result } : null; - }, - controller(args) { - var _a, _b; - const initialValue = (_a = args.params.value) !== null && _a !== void 0 ? _a : 0; - const drc = new DefiniteRangeConstraint$1({ - max: args.params.max, - min: args.params.min, - }); - const v = createValue$1(initialValue, { - constraint: drc, - }); - const vc = new SliderTextController$1(args.document, Object.assign(Object.assign({}, createSliderTextProps$1({ - formatter: (_b = args.params.format) !== null && _b !== void 0 ? _b : numberToString, - keyScale: createValue$1(1), - max: drc.values.value('max'), - min: drc.values.value('min'), - pointerScale: getSuitablePointerScale$1(args.params, initialValue), - })), { parser: parseNumber$1, value: v, viewProps: args.viewProps })); - return new LabeledValueBladeController$1(args.document, { - blade: args.blade, - props: ValueMap$1.fromObject({ - label: args.params.label, - }), - value: v, - valueController: vc, - }); - }, - api(args) { - if (!(args.controller instanceof LabeledValueBladeController$1)) { - return null; - } - if (!(args.controller.valueController instanceof SliderTextController$1)) { - return null; - } - return new SliderBladeApi(args.controller); - }, - }; - - const TextBladePlugin = (function () { - return { - id: 'text', - type: 'blade', - core: VERSION$1, - accept(params) { - const result = parseRecord$1(params, (p) => ({ - parse: p.required.function, - value: p.required.raw, - view: p.required.constant('text'), - format: p.optional.function, - label: p.optional.string, - })); - return result ? { params: result } : null; - }, - controller(args) { - var _a; - const v = createValue$1(args.params.value); - const ic = new TextController$1(args.document, { - parser: args.params.parse, - props: ValueMap$1.fromObject({ - formatter: (_a = args.params.format) !== null && _a !== void 0 ? _a : ((v) => String(v)), - }), - value: v, - viewProps: args.viewProps, - }); - return new LabeledValueBladeController$1(args.document, { - blade: args.blade, - props: ValueMap$1.fromObject({ - label: args.params.label, - }), - value: v, - valueController: ic, - }); - }, - api(args) { - if (!(args.controller instanceof LabeledValueBladeController$1)) { - return null; - } - if (!(args.controller.valueController instanceof TextController$1)) { - return null; - } - return new TextBladeApi(args.controller); - }, - }; - })(); - - function createDefaultWrapperElement(doc) { - const elem = doc.createElement('div'); - elem.classList.add(ClassName$1('dfw')()); - if (doc.body) { - doc.body.appendChild(elem); - } - return elem; - } - function embedStyle(doc, id, css) { - if (doc.querySelector(`style[data-tp-style=${id}]`)) { - return; - } - const styleElem = doc.createElement('style'); - styleElem.dataset.tpStyle = id; - styleElem.textContent = css; - doc.head.appendChild(styleElem); - } - /** - * The root pane of Tweakpane. - */ - class Pane extends RootApi { - constructor(opt_config) { - var _a, _b; - const config = opt_config !== null && opt_config !== void 0 ? opt_config : {}; - const doc = (_a = config.document) !== null && _a !== void 0 ? _a : getWindowDocument(); - const pool = createDefaultPluginPool(); - const rootController = new RootController(doc, { - expanded: config.expanded, - blade: createBlade$1(), - props: ValueMap$1.fromObject({ - title: config.title, - }), - viewProps: ViewProps$1.create(), - }); - super(rootController, pool); - this.pool_ = pool; - this.containerElem_ = (_b = config.container) !== null && _b !== void 0 ? _b : createDefaultWrapperElement(doc); - this.containerElem_.appendChild(this.element); - this.doc_ = doc; - this.usesDefaultWrapper_ = !config.container; - this.setUpDefaultPlugins_(); - } - get document() { - if (!this.doc_) { - throw TpError$1.alreadyDisposed(); - } - return this.doc_; - } - dispose() { - const containerElem = this.containerElem_; - if (!containerElem) { - throw TpError$1.alreadyDisposed(); - } - if (this.usesDefaultWrapper_) { - const parentElem = containerElem.parentElement; - if (parentElem) { - parentElem.removeChild(containerElem); - } - } - this.containerElem_ = null; - this.doc_ = null; - super.dispose(); - } - registerPlugin(bundle) { - if (bundle.css) { - embedStyle(this.document, `plugin-${bundle.id}`, bundle.css); - } - const plugins = 'plugin' in bundle - ? [bundle.plugin] - : 'plugins' in bundle - ? bundle.plugins - : []; - plugins.forEach((p) => { - this.pool_.register(bundle.id, p); - }); - } - setUpDefaultPlugins_() { - this.registerPlugin({ - id: 'default', - // NOTE: This string literal will be replaced with the default CSS by Rollup at the compilation time - css: '.tp-tbiv_b,.tp-coltxtv_ms,.tp-colswv_b,.tp-ckbv_i,.tp-sglv_i,.tp-mllv_i,.tp-grlv_g,.tp-txtv_i,.tp-p2dpv_p,.tp-colswv_sw,.tp-rotv_b,.tp-fldv_b,.tp-p2dv_b,.tp-btnv_b,.tp-lstv_s{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:rgba(0,0,0,0);border-width:0;font-family:inherit;font-size:inherit;font-weight:inherit;margin:0;outline:none;padding:0}.tp-p2dv_b,.tp-btnv_b,.tp-lstv_s{background-color:var(--btn-bg);border-radius:var(--bld-br);color:var(--btn-fg);cursor:pointer;display:block;font-weight:bold;height:var(--cnt-usz);line-height:var(--cnt-usz);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tp-p2dv_b:hover,.tp-btnv_b:hover,.tp-lstv_s:hover{background-color:var(--btn-bg-h)}.tp-p2dv_b:focus,.tp-btnv_b:focus,.tp-lstv_s:focus{background-color:var(--btn-bg-f)}.tp-p2dv_b:active,.tp-btnv_b:active,.tp-lstv_s:active{background-color:var(--btn-bg-a)}.tp-p2dv_b:disabled,.tp-btnv_b:disabled,.tp-lstv_s:disabled{opacity:.5}.tp-rotv_c>.tp-cntv.tp-v-lst,.tp-tbpv_c>.tp-cntv.tp-v-lst,.tp-fldv_c>.tp-cntv.tp-v-lst{margin-bottom:calc(-1*var(--cnt-vp))}.tp-rotv_c>.tp-fldv.tp-v-lst .tp-fldv_c,.tp-tbpv_c>.tp-fldv.tp-v-lst .tp-fldv_c,.tp-fldv_c>.tp-fldv.tp-v-lst .tp-fldv_c{border-bottom-left-radius:0}.tp-rotv_c>.tp-fldv.tp-v-lst .tp-fldv_b,.tp-tbpv_c>.tp-fldv.tp-v-lst .tp-fldv_b,.tp-fldv_c>.tp-fldv.tp-v-lst .tp-fldv_b{border-bottom-left-radius:0}.tp-rotv_c>*:not(.tp-v-fst),.tp-tbpv_c>*:not(.tp-v-fst),.tp-fldv_c>*:not(.tp-v-fst){margin-top:var(--cnt-usp)}.tp-rotv_c>.tp-sprv:not(.tp-v-fst),.tp-tbpv_c>.tp-sprv:not(.tp-v-fst),.tp-fldv_c>.tp-sprv:not(.tp-v-fst),.tp-rotv_c>.tp-cntv:not(.tp-v-fst),.tp-tbpv_c>.tp-cntv:not(.tp-v-fst),.tp-fldv_c>.tp-cntv:not(.tp-v-fst){margin-top:var(--cnt-vp)}.tp-rotv_c>.tp-sprv+*:not(.tp-v-hidden),.tp-tbpv_c>.tp-sprv+*:not(.tp-v-hidden),.tp-fldv_c>.tp-sprv+*:not(.tp-v-hidden),.tp-rotv_c>.tp-cntv+*:not(.tp-v-hidden),.tp-tbpv_c>.tp-cntv+*:not(.tp-v-hidden),.tp-fldv_c>.tp-cntv+*:not(.tp-v-hidden){margin-top:var(--cnt-vp)}.tp-rotv_c>.tp-sprv:not(.tp-v-hidden)+.tp-sprv,.tp-tbpv_c>.tp-sprv:not(.tp-v-hidden)+.tp-sprv,.tp-fldv_c>.tp-sprv:not(.tp-v-hidden)+.tp-sprv,.tp-rotv_c>.tp-cntv:not(.tp-v-hidden)+.tp-cntv,.tp-tbpv_c>.tp-cntv:not(.tp-v-hidden)+.tp-cntv,.tp-fldv_c>.tp-cntv:not(.tp-v-hidden)+.tp-cntv{margin-top:0}.tp-tbpv_c>.tp-cntv,.tp-fldv_c>.tp-cntv{margin-left:4px}.tp-tbpv_c>.tp-fldv>.tp-fldv_b,.tp-fldv_c>.tp-fldv>.tp-fldv_b{border-top-left-radius:var(--bld-br);border-bottom-left-radius:var(--bld-br)}.tp-tbpv_c>.tp-fldv.tp-fldv-expanded>.tp-fldv_b,.tp-fldv_c>.tp-fldv.tp-fldv-expanded>.tp-fldv_b{border-bottom-left-radius:0}.tp-tbpv_c .tp-fldv>.tp-fldv_c,.tp-fldv_c .tp-fldv>.tp-fldv_c{border-bottom-left-radius:var(--bld-br)}.tp-tbpv_c>.tp-cntv+.tp-fldv>.tp-fldv_b,.tp-fldv_c>.tp-cntv+.tp-fldv>.tp-fldv_b{border-top-left-radius:0}.tp-tbpv_c>.tp-cntv+.tp-tabv>.tp-tabv_t,.tp-fldv_c>.tp-cntv+.tp-tabv>.tp-tabv_t{border-top-left-radius:0}.tp-tbpv_c>.tp-tabv>.tp-tabv_t,.tp-fldv_c>.tp-tabv>.tp-tabv_t{border-top-left-radius:var(--bld-br)}.tp-tbpv_c .tp-tabv>.tp-tabv_c,.tp-fldv_c .tp-tabv>.tp-tabv_c{border-bottom-left-radius:var(--bld-br)}.tp-rotv_b,.tp-fldv_b{background-color:var(--cnt-bg);color:var(--cnt-fg);cursor:pointer;display:block;height:calc(var(--cnt-usz) + 4px);line-height:calc(var(--cnt-usz) + 4px);overflow:hidden;padding-left:var(--cnt-hp);padding-right:calc(4px + var(--cnt-usz) + var(--cnt-hp));position:relative;text-align:left;text-overflow:ellipsis;white-space:nowrap;width:100%;transition:border-radius .2s ease-in-out .2s}.tp-rotv_b:hover,.tp-fldv_b:hover{background-color:var(--cnt-bg-h)}.tp-rotv_b:focus,.tp-fldv_b:focus{background-color:var(--cnt-bg-f)}.tp-rotv_b:active,.tp-fldv_b:active{background-color:var(--cnt-bg-a)}.tp-rotv_b:disabled,.tp-fldv_b:disabled{opacity:.5}.tp-rotv_m,.tp-fldv_m{background:linear-gradient(to left, var(--cnt-fg), var(--cnt-fg) 2px, transparent 2px, transparent 4px, var(--cnt-fg) 4px);border-radius:2px;bottom:0;content:"";display:block;height:6px;right:calc(var(--cnt-hp) + (var(--cnt-usz) + 4px - 6px)/2 - 2px);margin:auto;opacity:.5;position:absolute;top:0;transform:rotate(90deg);transition:transform .2s ease-in-out;width:6px}.tp-rotv.tp-rotv-expanded .tp-rotv_m,.tp-fldv.tp-fldv-expanded>.tp-fldv_b>.tp-fldv_m{transform:none}.tp-rotv_c,.tp-fldv_c{box-sizing:border-box;height:0;opacity:0;overflow:hidden;padding-bottom:0;padding-top:0;position:relative;transition:height .2s ease-in-out,opacity .2s linear,padding .2s ease-in-out}.tp-rotv.tp-rotv-cpl:not(.tp-rotv-expanded) .tp-rotv_c,.tp-fldv.tp-fldv-cpl:not(.tp-fldv-expanded)>.tp-fldv_c{display:none}.tp-rotv.tp-rotv-expanded .tp-rotv_c,.tp-fldv.tp-fldv-expanded>.tp-fldv_c{opacity:1;padding-bottom:var(--cnt-vp);padding-top:var(--cnt-vp);transform:none;overflow:visible;transition:height .2s ease-in-out,opacity .2s linear .2s,padding .2s ease-in-out}.tp-txtv_i,.tp-p2dpv_p,.tp-colswv_sw{background-color:var(--in-bg);border-radius:var(--bld-br);box-sizing:border-box;color:var(--in-fg);font-family:inherit;height:var(--cnt-usz);line-height:var(--cnt-usz);min-width:0;width:100%}.tp-txtv_i:hover,.tp-p2dpv_p:hover,.tp-colswv_sw:hover{background-color:var(--in-bg-h)}.tp-txtv_i:focus,.tp-p2dpv_p:focus,.tp-colswv_sw:focus{background-color:var(--in-bg-f)}.tp-txtv_i:active,.tp-p2dpv_p:active,.tp-colswv_sw:active{background-color:var(--in-bg-a)}.tp-txtv_i:disabled,.tp-p2dpv_p:disabled,.tp-colswv_sw:disabled{opacity:.5}.tp-lstv,.tp-coltxtv_m{position:relative}.tp-lstv_s{padding:0 20px 0 4px;width:100%}.tp-lstv_m,.tp-coltxtv_mm{bottom:0;margin:auto;pointer-events:none;position:absolute;right:2px;top:0}.tp-lstv_m svg,.tp-coltxtv_mm svg{bottom:0;height:16px;margin:auto;position:absolute;right:0;top:0;width:16px}.tp-lstv_m svg path,.tp-coltxtv_mm svg path{fill:currentColor}.tp-sglv_i,.tp-mllv_i,.tp-grlv_g{background-color:var(--mo-bg);border-radius:var(--bld-br);box-sizing:border-box;color:var(--mo-fg);height:var(--cnt-usz);scrollbar-color:currentColor rgba(0,0,0,0);scrollbar-width:thin;width:100%}.tp-sglv_i::-webkit-scrollbar,.tp-mllv_i::-webkit-scrollbar,.tp-grlv_g::-webkit-scrollbar{height:8px;width:8px}.tp-sglv_i::-webkit-scrollbar-corner,.tp-mllv_i::-webkit-scrollbar-corner,.tp-grlv_g::-webkit-scrollbar-corner{background-color:rgba(0,0,0,0)}.tp-sglv_i::-webkit-scrollbar-thumb,.tp-mllv_i::-webkit-scrollbar-thumb,.tp-grlv_g::-webkit-scrollbar-thumb{background-clip:padding-box;background-color:currentColor;border:rgba(0,0,0,0) solid 2px;border-radius:4px}.tp-pndtxtv,.tp-coltxtv_w{display:flex}.tp-pndtxtv_a,.tp-coltxtv_c{width:100%}.tp-pndtxtv_a+.tp-pndtxtv_a,.tp-coltxtv_c+.tp-pndtxtv_a,.tp-pndtxtv_a+.tp-coltxtv_c,.tp-coltxtv_c+.tp-coltxtv_c{margin-left:2px}.tp-rotv{--bs-bg: var(--tp-base-background-color, hsl(230, 7%, 17%));--bs-br: var(--tp-base-border-radius, 6px);--bs-ff: var(--tp-base-font-family, Roboto Mono, Source Code Pro, Menlo, Courier, monospace);--bs-sh: var(--tp-base-shadow-color, rgba(0, 0, 0, 0.2));--bld-br: var(--tp-blade-border-radius, 2px);--bld-hp: var(--tp-blade-horizontal-padding, 4px);--bld-vw: var(--tp-blade-value-width, 160px);--btn-bg: var(--tp-button-background-color, hsl(230, 7%, 70%));--btn-bg-a: var(--tp-button-background-color-active, #d6d7db);--btn-bg-f: var(--tp-button-background-color-focus, #c8cad0);--btn-bg-h: var(--tp-button-background-color-hover, #bbbcc4);--btn-fg: var(--tp-button-foreground-color, hsl(230, 7%, 17%));--cnt-bg: var(--tp-container-background-color, rgba(187, 188, 196, 0.1));--cnt-bg-a: var(--tp-container-background-color-active, rgba(187, 188, 196, 0.25));--cnt-bg-f: var(--tp-container-background-color-focus, rgba(187, 188, 196, 0.2));--cnt-bg-h: var(--tp-container-background-color-hover, rgba(187, 188, 196, 0.15));--cnt-fg: var(--tp-container-foreground-color, hsl(230, 7%, 75%));--cnt-hp: var(--tp-container-horizontal-padding, 4px);--cnt-vp: var(--tp-container-vertical-padding, 4px);--cnt-usp: var(--tp-container-unit-spacing, 4px);--cnt-usz: var(--tp-container-unit-size, 20px);--in-bg: var(--tp-input-background-color, rgba(187, 188, 196, 0.1));--in-bg-a: var(--tp-input-background-color-active, rgba(187, 188, 196, 0.25));--in-bg-f: var(--tp-input-background-color-focus, rgba(187, 188, 196, 0.2));--in-bg-h: var(--tp-input-background-color-hover, rgba(187, 188, 196, 0.15));--in-fg: var(--tp-input-foreground-color, hsl(230, 7%, 75%));--lbl-fg: var(--tp-label-foreground-color, rgba(187, 188, 196, 0.7));--mo-bg: var(--tp-monitor-background-color, rgba(0, 0, 0, 0.2));--mo-fg: var(--tp-monitor-foreground-color, rgba(187, 188, 196, 0.7));--grv-fg: var(--tp-groove-foreground-color, rgba(187, 188, 196, 0.1))}.tp-btnv_b{width:100%}.tp-btnv_t{text-align:center}.tp-ckbv_l{display:block;position:relative}.tp-ckbv_i{left:0;opacity:0;position:absolute;top:0}.tp-ckbv_w{background-color:var(--in-bg);border-radius:var(--bld-br);cursor:pointer;display:block;height:var(--cnt-usz);position:relative;width:var(--cnt-usz)}.tp-ckbv_w svg{display:block;height:16px;inset:0;margin:auto;opacity:0;position:absolute;width:16px}.tp-ckbv_w svg path{fill:none;stroke:var(--in-fg);stroke-width:2}.tp-ckbv_i:hover+.tp-ckbv_w{background-color:var(--in-bg-h)}.tp-ckbv_i:focus+.tp-ckbv_w{background-color:var(--in-bg-f)}.tp-ckbv_i:active+.tp-ckbv_w{background-color:var(--in-bg-a)}.tp-ckbv_i:checked+.tp-ckbv_w svg{opacity:1}.tp-ckbv.tp-v-disabled .tp-ckbv_w{opacity:.5}.tp-colv{position:relative}.tp-colv_h{display:flex}.tp-colv_s{flex-grow:0;flex-shrink:0;width:var(--cnt-usz)}.tp-colv_t{flex:1;margin-left:4px}.tp-colv_p{height:0;margin-top:0;opacity:0;overflow:hidden;transition:height .2s ease-in-out,opacity .2s linear,margin .2s ease-in-out}.tp-colv.tp-colv-expanded.tp-colv-cpl .tp-colv_p{overflow:visible}.tp-colv.tp-colv-expanded .tp-colv_p{margin-top:var(--cnt-usp);opacity:1}.tp-colv .tp-popv{left:calc(-1*var(--cnt-hp));right:calc(-1*var(--cnt-hp));top:var(--cnt-usz)}.tp-colpv_h,.tp-colpv_ap{margin-left:6px;margin-right:6px}.tp-colpv_h{margin-top:var(--cnt-usp)}.tp-colpv_rgb{display:flex;margin-top:var(--cnt-usp);width:100%}.tp-colpv_a{display:flex;margin-top:var(--cnt-vp);padding-top:calc(var(--cnt-vp) + 2px);position:relative}.tp-colpv_a::before{background-color:var(--grv-fg);content:"";height:2px;left:calc(-1*var(--cnt-hp));position:absolute;right:calc(-1*var(--cnt-hp));top:0}.tp-colpv.tp-v-disabled .tp-colpv_a::before{opacity:.5}.tp-colpv_ap{align-items:center;display:flex;flex:3}.tp-colpv_at{flex:1;margin-left:4px}.tp-svpv{border-radius:var(--bld-br);outline:none;overflow:hidden;position:relative}.tp-svpv.tp-v-disabled{opacity:.5}.tp-svpv_c{cursor:crosshair;display:block;height:calc(var(--cnt-usz)*4);width:100%}.tp-svpv_m{border-radius:100%;border:rgba(255,255,255,.75) solid 2px;box-sizing:border-box;filter:drop-shadow(0 0 1px rgba(0, 0, 0, 0.3));height:12px;margin-left:-6px;margin-top:-6px;pointer-events:none;position:absolute;width:12px}.tp-svpv:focus .tp-svpv_m{border-color:#fff}.tp-hplv{cursor:pointer;height:var(--cnt-usz);outline:none;position:relative}.tp-hplv.tp-v-disabled{opacity:.5}.tp-hplv_c{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAABCAYAAABubagXAAAAQ0lEQVQoU2P8z8Dwn0GCgQEDi2OK/RBgYHjBgIpfovFh8j8YBIgzFGQxuqEgPhaDOT5gOhPkdCxOZeBg+IDFZZiGAgCaSSMYtcRHLgAAAABJRU5ErkJggg==);background-position:left top;background-repeat:no-repeat;background-size:100% 100%;border-radius:2px;display:block;height:4px;left:0;margin-top:-2px;position:absolute;top:50%;width:100%}.tp-hplv_m{border-radius:var(--bld-br);border:rgba(255,255,255,.75) solid 2px;box-shadow:0 0 2px rgba(0,0,0,.1);box-sizing:border-box;height:12px;left:50%;margin-left:-6px;margin-top:-6px;pointer-events:none;position:absolute;top:50%;width:12px}.tp-hplv:focus .tp-hplv_m{border-color:#fff}.tp-aplv{cursor:pointer;height:var(--cnt-usz);outline:none;position:relative;width:100%}.tp-aplv.tp-v-disabled{opacity:.5}.tp-aplv_b{background-color:#fff;background-image:linear-gradient(to top right, #ddd 25%, transparent 25%, transparent 75%, #ddd 75%),linear-gradient(to top right, #ddd 25%, transparent 25%, transparent 75%, #ddd 75%);background-size:4px 4px;background-position:0 0,2px 2px;border-radius:2px;display:block;height:4px;left:0;margin-top:-2px;overflow:hidden;position:absolute;top:50%;width:100%}.tp-aplv_c{inset:0;position:absolute}.tp-aplv_m{background-color:#fff;background-image:linear-gradient(to top right, #ddd 25%, transparent 25%, transparent 75%, #ddd 75%),linear-gradient(to top right, #ddd 25%, transparent 25%, transparent 75%, #ddd 75%);background-size:12px 12px;background-position:0 0,6px 6px;border-radius:var(--bld-br);box-shadow:0 0 2px rgba(0,0,0,.1);height:12px;left:50%;margin-left:-6px;margin-top:-6px;overflow:hidden;pointer-events:none;position:absolute;top:50%;width:12px}.tp-aplv_p{border-radius:var(--bld-br);border:rgba(255,255,255,.75) solid 2px;box-sizing:border-box;inset:0;position:absolute}.tp-aplv:focus .tp-aplv_p{border-color:#fff}.tp-colswv{background-color:#fff;background-image:linear-gradient(to top right, #ddd 25%, transparent 25%, transparent 75%, #ddd 75%),linear-gradient(to top right, #ddd 25%, transparent 25%, transparent 75%, #ddd 75%);background-size:10px 10px;background-position:0 0,5px 5px;border-radius:var(--bld-br);overflow:hidden}.tp-colswv.tp-v-disabled{opacity:.5}.tp-colswv_sw{border-radius:0}.tp-colswv_b{cursor:pointer;display:block;height:var(--cnt-usz);left:0;position:absolute;top:0;width:var(--cnt-usz)}.tp-colswv_b:focus::after{border:rgba(255,255,255,.75) solid 2px;border-radius:var(--bld-br);content:"";display:block;inset:0;position:absolute}.tp-coltxtv{display:flex;width:100%}.tp-coltxtv_m{margin-right:4px}.tp-coltxtv_ms{border-radius:var(--bld-br);color:var(--lbl-fg);cursor:pointer;height:var(--cnt-usz);line-height:var(--cnt-usz);padding:0 18px 0 4px}.tp-coltxtv_ms:hover{background-color:var(--in-bg-h)}.tp-coltxtv_ms:focus{background-color:var(--in-bg-f)}.tp-coltxtv_ms:active{background-color:var(--in-bg-a)}.tp-coltxtv_mm{color:var(--lbl-fg)}.tp-coltxtv.tp-v-disabled .tp-coltxtv_mm{opacity:.5}.tp-coltxtv_w{flex:1}.tp-dfwv{position:absolute;top:8px;right:8px;width:256px}.tp-fldv{position:relative}.tp-fldv_t{padding-left:4px}.tp-fldv_b:disabled .tp-fldv_m{display:none}.tp-fldv_c{padding-left:4px}.tp-fldv_i{bottom:0;color:var(--cnt-bg);left:0;overflow:hidden;position:absolute;top:calc(var(--cnt-usz) + 4px);width:max(var(--bs-br),4px)}.tp-fldv_i::before{background-color:currentColor;bottom:0;content:"";left:0;position:absolute;top:0;width:4px}.tp-fldv_b:hover+.tp-fldv_i{color:var(--cnt-bg-h)}.tp-fldv_b:focus+.tp-fldv_i{color:var(--cnt-bg-f)}.tp-fldv_b:active+.tp-fldv_i{color:var(--cnt-bg-a)}.tp-fldv.tp-v-disabled>.tp-fldv_i{opacity:.5}.tp-grlv{position:relative}.tp-grlv_g{display:block;height:calc(var(--cnt-usz)*3)}.tp-grlv_g polyline{fill:none;stroke:var(--mo-fg);stroke-linejoin:round}.tp-grlv_t{margin-top:-4px;transition:left .05s,top .05s;visibility:hidden}.tp-grlv_t.tp-grlv_t-a{visibility:visible}.tp-grlv_t.tp-grlv_t-in{transition:none}.tp-grlv.tp-v-disabled .tp-grlv_g{opacity:.5}.tp-grlv .tp-ttv{background-color:var(--mo-fg)}.tp-grlv .tp-ttv::before{border-top-color:var(--mo-fg)}.tp-lblv{align-items:center;display:flex;line-height:1.3;padding-left:var(--cnt-hp);padding-right:var(--cnt-hp)}.tp-lblv.tp-lblv-nol{display:block}.tp-lblv_l{color:var(--lbl-fg);flex:1;-webkit-hyphens:auto;hyphens:auto;overflow:hidden;padding-left:4px;padding-right:16px}.tp-lblv.tp-v-disabled .tp-lblv_l{opacity:.5}.tp-lblv.tp-lblv-nol .tp-lblv_l{display:none}.tp-lblv_v{align-self:flex-start;flex-grow:0;flex-shrink:0;width:var(--bld-vw)}.tp-lblv.tp-lblv-nol .tp-lblv_v{width:100%}.tp-lstv_s{padding:0 20px 0 var(--bld-hp);width:100%}.tp-lstv_m{color:var(--btn-fg)}.tp-sglv_i{padding-left:var(--bld-hp);padding-right:var(--bld-hp)}.tp-sglv.tp-v-disabled .tp-sglv_i{opacity:.5}.tp-mllv_i{display:block;height:calc(var(--cnt-usz)*3);line-height:var(--cnt-usz);padding-left:var(--bld-hp);padding-right:var(--bld-hp);resize:none;white-space:pre}.tp-mllv.tp-v-disabled .tp-mllv_i{opacity:.5}.tp-p2dv{position:relative}.tp-p2dv_h{display:flex}.tp-p2dv_b{height:var(--cnt-usz);margin-right:4px;position:relative;width:var(--cnt-usz)}.tp-p2dv_b svg{display:block;height:16px;left:50%;margin-left:-8px;margin-top:-8px;position:absolute;top:50%;width:16px}.tp-p2dv_b svg path{stroke:currentColor;stroke-width:2}.tp-p2dv_b svg circle{fill:currentColor}.tp-p2dv_t{flex:1}.tp-p2dv_p{height:0;margin-top:0;opacity:0;overflow:hidden;transition:height .2s ease-in-out,opacity .2s linear,margin .2s ease-in-out}.tp-p2dv.tp-p2dv-expanded .tp-p2dv_p{margin-top:var(--cnt-usp);opacity:1}.tp-p2dv .tp-popv{left:calc(-1*var(--cnt-hp));right:calc(-1*var(--cnt-hp));top:var(--cnt-usz)}.tp-p2dpv{padding-left:calc(var(--cnt-usz) + 4px)}.tp-p2dpv_p{cursor:crosshair;height:0;overflow:hidden;padding-bottom:100%;position:relative}.tp-p2dpv.tp-v-disabled .tp-p2dpv_p{opacity:.5}.tp-p2dpv_g{display:block;height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%}.tp-p2dpv_ax{opacity:.1;stroke:var(--in-fg);stroke-dasharray:1}.tp-p2dpv_l{opacity:.5;stroke:var(--in-fg);stroke-dasharray:1}.tp-p2dpv_m{border:var(--in-fg) solid 1px;border-radius:50%;box-sizing:border-box;height:4px;margin-left:-2px;margin-top:-2px;position:absolute;width:4px}.tp-p2dpv_p:focus .tp-p2dpv_m{background-color:var(--in-fg);border-width:0}.tp-popv{background-color:var(--bs-bg);border-radius:var(--bs-br);box-shadow:0 2px 4px var(--bs-sh);display:none;max-width:var(--bld-vw);padding:var(--cnt-vp) var(--cnt-hp);position:absolute;visibility:hidden;z-index:1000}.tp-popv.tp-popv-v{display:block;visibility:visible}.tp-sldv.tp-v-disabled{opacity:.5}.tp-sldv_t{box-sizing:border-box;cursor:pointer;height:var(--cnt-usz);margin:0 6px;outline:none;position:relative}.tp-sldv_t::before{background-color:var(--in-bg);border-radius:1px;content:"";display:block;height:2px;inset:0;margin:auto;position:absolute}.tp-sldv_k{height:100%;left:0;position:absolute;top:0}.tp-sldv_k::before{background-color:var(--in-fg);border-radius:1px;content:"";display:block;height:2px;inset:0;margin-bottom:auto;margin-top:auto;position:absolute}.tp-sldv_k::after{background-color:var(--btn-bg);border-radius:var(--bld-br);bottom:0;content:"";display:block;height:12px;margin-bottom:auto;margin-top:auto;position:absolute;right:-6px;top:0;width:12px}.tp-sldv_t:hover .tp-sldv_k::after{background-color:var(--btn-bg-h)}.tp-sldv_t:focus .tp-sldv_k::after{background-color:var(--btn-bg-f)}.tp-sldv_t:active .tp-sldv_k::after{background-color:var(--btn-bg-a)}.tp-sldtxtv{display:flex}.tp-sldtxtv_s{flex:2}.tp-sldtxtv_t{flex:1;margin-left:4px}.tp-tabv{position:relative}.tp-tabv_t{align-items:flex-end;color:var(--cnt-bg);display:flex;overflow:hidden;position:relative}.tp-tabv_t:hover{color:var(--cnt-bg-h)}.tp-tabv_t:has(*:focus){color:var(--cnt-bg-f)}.tp-tabv_t:has(*:active){color:var(--cnt-bg-a)}.tp-tabv_t::before{background-color:currentColor;bottom:0;content:"";height:2px;left:0;pointer-events:none;position:absolute;right:0}.tp-tabv.tp-v-disabled .tp-tabv_t::before{opacity:.5}.tp-tabv.tp-tabv-nop .tp-tabv_t{height:calc(var(--cnt-usz) + 4px);position:relative}.tp-tabv.tp-tabv-nop .tp-tabv_t::before{background-color:var(--cnt-bg);bottom:0;content:"";height:2px;left:0;position:absolute;right:0}.tp-tabv_i{bottom:0;color:var(--cnt-bg);left:0;overflow:hidden;position:absolute;top:calc(var(--cnt-usz) + 4px);width:max(var(--bs-br),4px)}.tp-tabv_i::before{background-color:currentColor;bottom:0;content:"";left:0;position:absolute;top:0;width:4px}.tp-tabv_t:hover+.tp-tabv_i{color:var(--cnt-bg-h)}.tp-tabv_t:has(*:focus)+.tp-tabv_i{color:var(--cnt-bg-f)}.tp-tabv_t:has(*:active)+.tp-tabv_i{color:var(--cnt-bg-a)}.tp-tabv.tp-v-disabled>.tp-tabv_i{opacity:.5}.tp-tbiv{flex:1;min-width:0;position:relative}.tp-tbiv+.tp-tbiv{margin-left:2px}.tp-tbiv+.tp-tbiv.tp-v-disabled::before{opacity:.5}.tp-tbiv_b{display:block;padding-left:calc(var(--cnt-hp) + 4px);padding-right:calc(var(--cnt-hp) + 4px);position:relative;width:100%}.tp-tbiv_b:disabled{opacity:.5}.tp-tbiv_b::before{background-color:var(--cnt-bg);content:"";inset:0 0 2px;pointer-events:none;position:absolute}.tp-tbiv_b:hover::before{background-color:var(--cnt-bg-h)}.tp-tbiv_b:focus::before{background-color:var(--cnt-bg-f)}.tp-tbiv_b:active::before{background-color:var(--cnt-bg-a)}.tp-tbiv_t{color:var(--cnt-fg);height:calc(var(--cnt-usz) + 4px);line-height:calc(var(--cnt-usz) + 4px);opacity:.5;overflow:hidden;position:relative;text-overflow:ellipsis}.tp-tbiv.tp-tbiv-sel .tp-tbiv_t{opacity:1}.tp-tbpv_c{padding-bottom:var(--cnt-vp);padding-left:4px;padding-top:var(--cnt-vp)}.tp-txtv{position:relative}.tp-txtv_i{padding-left:var(--bld-hp);padding-right:var(--bld-hp)}.tp-txtv.tp-txtv-fst .tp-txtv_i{border-bottom-right-radius:0;border-top-right-radius:0}.tp-txtv.tp-txtv-mid .tp-txtv_i{border-radius:0}.tp-txtv.tp-txtv-lst .tp-txtv_i{border-bottom-left-radius:0;border-top-left-radius:0}.tp-txtv.tp-txtv-num .tp-txtv_i{text-align:right}.tp-txtv.tp-txtv-drg .tp-txtv_i{opacity:.3}.tp-txtv_k{cursor:pointer;height:100%;left:calc(var(--bld-hp) - 5px);position:absolute;top:0;width:12px}.tp-txtv_k::before{background-color:var(--in-fg);border-radius:1px;bottom:0;content:"";height:calc(var(--cnt-usz) - 4px);left:50%;margin-bottom:auto;margin-left:-1px;margin-top:auto;opacity:.1;position:absolute;top:0;transition:border-radius .1s,height .1s,transform .1s,width .1s;width:2px}.tp-txtv_k:hover::before,.tp-txtv.tp-txtv-drg .tp-txtv_k::before{opacity:1}.tp-txtv.tp-txtv-drg .tp-txtv_k::before{border-radius:50%;height:4px;transform:translateX(-1px);width:4px}.tp-txtv_g{bottom:0;display:block;height:8px;left:50%;margin:auto;overflow:visible;pointer-events:none;position:absolute;top:0;visibility:hidden;width:100%}.tp-txtv.tp-txtv-drg .tp-txtv_g{visibility:visible}.tp-txtv_gb{fill:none;stroke:var(--in-fg);stroke-dasharray:1}.tp-txtv_gh{fill:none;stroke:var(--in-fg)}.tp-txtv .tp-ttv{margin-left:6px;visibility:hidden}.tp-txtv.tp-txtv-drg .tp-ttv{visibility:visible}.tp-ttv{background-color:var(--in-fg);border-radius:var(--bld-br);color:var(--bs-bg);padding:2px 4px;pointer-events:none;position:absolute;transform:translate(-50%, -100%)}.tp-ttv::before{border-color:var(--in-fg) rgba(0,0,0,0) rgba(0,0,0,0) rgba(0,0,0,0);border-style:solid;border-width:2px;box-sizing:border-box;content:"";font-size:.9em;height:4px;left:50%;margin-left:-2px;position:absolute;top:100%;width:4px}.tp-rotv{background-color:var(--bs-bg);border-radius:var(--bs-br);box-shadow:0 2px 4px var(--bs-sh);font-family:var(--bs-ff);font-size:11px;font-weight:500;line-height:1;text-align:left}.tp-rotv_b{border-bottom-left-radius:var(--bs-br);border-bottom-right-radius:var(--bs-br);border-top-left-radius:var(--bs-br);border-top-right-radius:var(--bs-br);padding-left:calc(4px + var(--cnt-usz) + var(--cnt-hp));text-align:center}.tp-rotv.tp-rotv-expanded .tp-rotv_b{border-bottom-left-radius:0;border-bottom-right-radius:0;transition-delay:0s;transition-duration:0s}.tp-rotv.tp-rotv-not>.tp-rotv_b{display:none}.tp-rotv_b:disabled .tp-rotv_m{display:none}.tp-rotv_c>.tp-fldv.tp-v-lst>.tp-fldv_c{border-bottom-left-radius:var(--bs-br);border-bottom-right-radius:var(--bs-br)}.tp-rotv_c>.tp-fldv.tp-v-lst>.tp-fldv_i{border-bottom-left-radius:var(--bs-br)}.tp-rotv_c>.tp-fldv.tp-v-lst:not(.tp-fldv-expanded)>.tp-fldv_b{border-bottom-left-radius:var(--bs-br);border-bottom-right-radius:var(--bs-br)}.tp-rotv_c>.tp-fldv.tp-v-lst.tp-fldv-expanded>.tp-fldv_b{transition-delay:0s;transition-duration:0s}.tp-rotv_c .tp-fldv.tp-v-vlst:not(.tp-fldv-expanded)>.tp-fldv_b{border-bottom-right-radius:var(--bs-br)}.tp-rotv.tp-rotv-not .tp-rotv_c>.tp-fldv.tp-v-fst{margin-top:calc(-1*var(--cnt-vp))}.tp-rotv.tp-rotv-not .tp-rotv_c>.tp-fldv.tp-v-fst>.tp-fldv_b{border-top-left-radius:var(--bs-br);border-top-right-radius:var(--bs-br)}.tp-rotv_c>.tp-tabv.tp-v-lst>.tp-tabv_c{border-bottom-left-radius:var(--bs-br);border-bottom-right-radius:var(--bs-br)}.tp-rotv_c>.tp-tabv.tp-v-lst>.tp-tabv_i{border-bottom-left-radius:var(--bs-br)}.tp-rotv.tp-rotv-not .tp-rotv_c>.tp-tabv.tp-v-fst{margin-top:calc(-1*var(--cnt-vp))}.tp-rotv.tp-rotv-not .tp-rotv_c>.tp-tabv.tp-v-fst>.tp-tabv_t{border-top-left-radius:var(--bs-br);border-top-right-radius:var(--bs-br)}.tp-rotv.tp-v-disabled,.tp-rotv .tp-v-disabled{pointer-events:none}.tp-rotv.tp-v-hidden,.tp-rotv .tp-v-hidden{display:none}.tp-sprv_r{background-color:var(--grv-fg);border-width:0;display:block;height:2px;margin:0;width:100%}.tp-sprv.tp-v-disabled .tp-sprv_r{opacity:.5}', - plugins: [ - ListBladePlugin, - SeparatorBladePlugin, - SliderBladePlugin, - TabBladePlugin, - TextBladePlugin, - ], - }); - } - } - - new Semver$1('4.0.4'); - - function forceCast(v) { - return v; - } - function isEmpty(value) { - return value === null || value === undefined; - } - function isObject$1(value) { - return value !== null && typeof value === 'object'; - } - function isRecord(value) { - return value !== null && typeof value === 'object'; - } - function deepEqualsArray(a1, a2) { - if (a1.length !== a2.length) { - return false; - } - for (let i = 0; i < a1.length; i++) { - if (a1[i] !== a2[i]) { - return false; - } - } - return true; - } - function deepMerge(r1, r2) { - const keys = Array.from(new Set([...Object.keys(r1), ...Object.keys(r2)])); - return keys.reduce((result, key) => { - const v1 = r1[key]; - const v2 = r2[key]; - return isRecord(v1) && isRecord(v2) - ? Object.assign(Object.assign({}, result), { [key]: deepMerge(v1, v2) }) : Object.assign(Object.assign({}, result), { [key]: key in r2 ? v2 : v1 }); - }, {}); - } - - function isBinding(value) { - if (!isObject$1(value)) { - return false; - } - return 'target' in value; - } - - const CREATE_MESSAGE_MAP = { - alreadydisposed: () => 'View has been already disposed', - invalidparams: (context) => `Invalid parameters for '${context.name}'`, - nomatchingcontroller: (context) => `No matching controller for '${context.key}'`, - nomatchingview: (context) => `No matching view for '${JSON.stringify(context.params)}'`, - notbindable: () => `Value is not bindable`, - notcompatible: (context) => `Not compatible with plugin '${context.id}'`, - propertynotfound: (context) => `Property '${context.name}' not found`, - shouldneverhappen: () => 'This error should never happen', - }; - class TpError { - static alreadyDisposed() { - return new TpError({ type: 'alreadydisposed' }); - } - static notBindable() { - return new TpError({ - type: 'notbindable', - }); - } - static notCompatible(bundleId, id) { - return new TpError({ - type: 'notcompatible', - context: { - id: `${bundleId}.${id}`, - }, - }); - } - static propertyNotFound(name) { - return new TpError({ - type: 'propertynotfound', - context: { - name: name, - }, - }); - } - static shouldNeverHappen() { - return new TpError({ type: 'shouldneverhappen' }); - } - constructor(config) { - var _a; - this.message = - (_a = CREATE_MESSAGE_MAP[config.type](forceCast(config.context))) !== null && _a !== void 0 ? _a : 'Unexpected error'; - this.name = this.constructor.name; - this.stack = new Error(this.message).stack; - this.type = config.type; - } - toString() { - return this.message; - } - } - - class BindingTarget { - constructor(obj, key) { - this.obj_ = obj; - this.key = key; - } - static isBindable(obj) { - if (obj === null) { - return false; - } - if (typeof obj !== 'object' && typeof obj !== 'function') { - return false; - } - return true; - } - read() { - return this.obj_[this.key]; - } - write(value) { - this.obj_[this.key] = value; - } - writeProperty(name, value) { - const valueObj = this.read(); - if (!BindingTarget.isBindable(valueObj)) { - throw TpError.notBindable(); - } - if (!(name in valueObj)) { - throw TpError.propertyNotFound(name); - } - valueObj[name] = value; - } - } - - class Emitter { - constructor() { - this.observers_ = {}; - } - on(eventName, handler) { - let observers = this.observers_[eventName]; - if (!observers) { - observers = this.observers_[eventName] = []; - } - observers.push({ - handler: handler, - }); - return this; - } - off(eventName, handler) { - const observers = this.observers_[eventName]; - if (observers) { - this.observers_[eventName] = observers.filter((observer) => { - return observer.handler !== handler; - }); - } - return this; - } - emit(eventName, event) { - const observers = this.observers_[eventName]; - if (!observers) { - return; - } - observers.forEach((observer) => { - observer.handler(event); - }); - } - } - - class ComplexValue { - constructor(initialValue, config) { - var _a; - this.constraint_ = config === null || config === void 0 ? void 0 : config.constraint; - this.equals_ = (_a = config === null || config === void 0 ? void 0 : config.equals) !== null && _a !== void 0 ? _a : ((v1, v2) => v1 === v2); - this.emitter = new Emitter(); - this.rawValue_ = initialValue; - } - get constraint() { - return this.constraint_; - } - get rawValue() { - return this.rawValue_; - } - set rawValue(rawValue) { - this.setRawValue(rawValue, { - forceEmit: false, - last: true, - }); - } - setRawValue(rawValue, options) { - const opts = options !== null && options !== void 0 ? options : { - forceEmit: false, - last: true, - }; - const constrainedValue = this.constraint_ - ? this.constraint_.constrain(rawValue) - : rawValue; - const prevValue = this.rawValue_; - const changed = !this.equals_(prevValue, constrainedValue); - if (!changed && !opts.forceEmit) { - return; - } - this.emitter.emit('beforechange', { - sender: this, - }); - this.rawValue_ = constrainedValue; - this.emitter.emit('change', { - options: opts, - previousRawValue: prevValue, - rawValue: constrainedValue, - sender: this, - }); - } - } - - class PrimitiveValue { - constructor(initialValue) { - this.emitter = new Emitter(); - this.value_ = initialValue; - } - get rawValue() { - return this.value_; - } - set rawValue(value) { - this.setRawValue(value, { - forceEmit: false, - last: true, - }); - } - setRawValue(value, options) { - const opts = options !== null && options !== void 0 ? options : { - forceEmit: false, - last: true, - }; - const prevValue = this.value_; - if (prevValue === value && !opts.forceEmit) { - return; - } - this.emitter.emit('beforechange', { - sender: this, - }); - this.value_ = value; - this.emitter.emit('change', { - options: opts, - previousRawValue: prevValue, - rawValue: this.value_, - sender: this, - }); - } - } - - class ReadonlyPrimitiveValue { - constructor(value) { - this.emitter = new Emitter(); - this.onValueBeforeChange_ = this.onValueBeforeChange_.bind(this); - this.onValueChange_ = this.onValueChange_.bind(this); - this.value_ = value; - this.value_.emitter.on('beforechange', this.onValueBeforeChange_); - this.value_.emitter.on('change', this.onValueChange_); - } - get rawValue() { - return this.value_.rawValue; - } - onValueBeforeChange_(ev) { - this.emitter.emit('beforechange', Object.assign(Object.assign({}, ev), { sender: this })); - } - onValueChange_(ev) { - this.emitter.emit('change', Object.assign(Object.assign({}, ev), { sender: this })); - } - } - - function createValue(initialValue, config) { - const constraint = config === null || config === void 0 ? void 0 : config.constraint; - const equals = config === null || config === void 0 ? void 0 : config.equals; - if (!constraint && !equals) { - return new PrimitiveValue(initialValue); - } - return new ComplexValue(initialValue, config); - } - function createReadonlyValue(value) { - return [ - new ReadonlyPrimitiveValue(value), - (rawValue, options) => { - value.setRawValue(rawValue, options); - }, - ]; - } - - class ValueMap { - constructor(valueMap) { - this.emitter = new Emitter(); - this.valMap_ = valueMap; - for (const key in this.valMap_) { - const v = this.valMap_[key]; - v.emitter.on('change', () => { - this.emitter.emit('change', { - key: key, - sender: this, - }); - }); - } - } - static createCore(initialValue) { - const keys = Object.keys(initialValue); - return keys.reduce((o, key) => { - return Object.assign(o, { - [key]: createValue(initialValue[key]), - }); - }, {}); - } - static fromObject(initialValue) { - const core = this.createCore(initialValue); - return new ValueMap(core); - } - get(key) { - return this.valMap_[key].rawValue; - } - set(key, value) { - this.valMap_[key].rawValue = value; - } - value(key) { - return this.valMap_[key]; - } - } - - class DefiniteRangeConstraint { - constructor(config) { - this.values = ValueMap.fromObject({ - max: config.max, - min: config.min, - }); - } - constrain(value) { - const max = this.values.get('max'); - const min = this.values.get('min'); - return Math.min(Math.max(value, min), max); - } - } - - class RangeConstraint { - constructor(config) { - this.values = ValueMap.fromObject({ - max: config.max, - min: config.min, - }); - } - constrain(value) { - const max = this.values.get('max'); - const min = this.values.get('min'); - let result = value; - if (!isEmpty(min)) { - result = Math.max(result, min); - } - if (!isEmpty(max)) { - result = Math.min(result, max); - } - return result; - } - } - - class StepConstraint { - constructor(step, origin = 0) { - this.step = step; - this.origin = origin; - } - constrain(value) { - const o = this.origin % this.step; - const r = Math.round((value - o) / this.step); - return o + r * this.step; - } - } - - class NumberLiteralNode { - constructor(text) { - this.text = text; - } - evaluate() { - return Number(this.text); - } - toString() { - return this.text; - } - } - const BINARY_OPERATION_MAP = { - '**': (v1, v2) => Math.pow(v1, v2), - '*': (v1, v2) => v1 * v2, - '/': (v1, v2) => v1 / v2, - '%': (v1, v2) => v1 % v2, - '+': (v1, v2) => v1 + v2, - '-': (v1, v2) => v1 - v2, - '<<': (v1, v2) => v1 << v2, - '>>': (v1, v2) => v1 >> v2, - '>>>': (v1, v2) => v1 >>> v2, - '&': (v1, v2) => v1 & v2, - '^': (v1, v2) => v1 ^ v2, - '|': (v1, v2) => v1 | v2, - }; - class BinaryOperationNode { - constructor(operator, left, right) { - this.left = left; - this.operator = operator; - this.right = right; - } - evaluate() { - const op = BINARY_OPERATION_MAP[this.operator]; - if (!op) { - throw new Error(`unexpected binary operator: '${this.operator}`); - } - return op(this.left.evaluate(), this.right.evaluate()); - } - toString() { - return [ - 'b(', - this.left.toString(), - this.operator, - this.right.toString(), - ')', - ].join(' '); - } - } - const UNARY_OPERATION_MAP = { - '+': (v) => v, - '-': (v) => -v, - '~': (v) => ~v, - }; - class UnaryOperationNode { - constructor(operator, expr) { - this.operator = operator; - this.expression = expr; - } - evaluate() { - const op = UNARY_OPERATION_MAP[this.operator]; - if (!op) { - throw new Error(`unexpected unary operator: '${this.operator}`); - } - return op(this.expression.evaluate()); - } - toString() { - return ['u(', this.operator, this.expression.toString(), ')'].join(' '); - } - } - - function combineReader(parsers) { - return (text, cursor) => { - for (let i = 0; i < parsers.length; i++) { - const result = parsers[i](text, cursor); - if (result !== '') { - return result; - } - } - return ''; - }; - } - function readWhitespace(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^\s+/); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readNonZeroDigit(text, cursor) { - const ch = text.substr(cursor, 1); - return ch.match(/^[1-9]$/) ? ch : ''; - } - function readDecimalDigits(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^[0-9]+/); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readSignedInteger(text, cursor) { - const ds = readDecimalDigits(text, cursor); - if (ds !== '') { - return ds; - } - const sign = text.substr(cursor, 1); - cursor += 1; - if (sign !== '-' && sign !== '+') { - return ''; - } - const sds = readDecimalDigits(text, cursor); - if (sds === '') { - return ''; - } - return sign + sds; - } - function readExponentPart(text, cursor) { - const e = text.substr(cursor, 1); - cursor += 1; - if (e.toLowerCase() !== 'e') { - return ''; - } - const si = readSignedInteger(text, cursor); - if (si === '') { - return ''; - } - return e + si; - } - function readDecimalIntegerLiteral(text, cursor) { - const ch = text.substr(cursor, 1); - if (ch === '0') { - return ch; - } - const nzd = readNonZeroDigit(text, cursor); - cursor += nzd.length; - if (nzd === '') { - return ''; - } - return nzd + readDecimalDigits(text, cursor); - } - function readDecimalLiteral1(text, cursor) { - const dil = readDecimalIntegerLiteral(text, cursor); - cursor += dil.length; - if (dil === '') { - return ''; - } - const dot = text.substr(cursor, 1); - cursor += dot.length; - if (dot !== '.') { - return ''; - } - const dds = readDecimalDigits(text, cursor); - cursor += dds.length; - return dil + dot + dds + readExponentPart(text, cursor); - } - function readDecimalLiteral2(text, cursor) { - const dot = text.substr(cursor, 1); - cursor += dot.length; - if (dot !== '.') { - return ''; - } - const dds = readDecimalDigits(text, cursor); - cursor += dds.length; - if (dds === '') { - return ''; - } - return dot + dds + readExponentPart(text, cursor); - } - function readDecimalLiteral3(text, cursor) { - const dil = readDecimalIntegerLiteral(text, cursor); - cursor += dil.length; - if (dil === '') { - return ''; - } - return dil + readExponentPart(text, cursor); - } - const readDecimalLiteral = combineReader([ - readDecimalLiteral1, - readDecimalLiteral2, - readDecimalLiteral3, - ]); - function parseBinaryDigits(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^[01]+/); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readBinaryIntegerLiteral(text, cursor) { - const prefix = text.substr(cursor, 2); - cursor += prefix.length; - if (prefix.toLowerCase() !== '0b') { - return ''; - } - const bds = parseBinaryDigits(text, cursor); - if (bds === '') { - return ''; - } - return prefix + bds; - } - function readOctalDigits(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^[0-7]+/); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readOctalIntegerLiteral(text, cursor) { - const prefix = text.substr(cursor, 2); - cursor += prefix.length; - if (prefix.toLowerCase() !== '0o') { - return ''; - } - const ods = readOctalDigits(text, cursor); - if (ods === '') { - return ''; - } - return prefix + ods; - } - function readHexDigits(text, cursor) { - var _a; - const m = text.substr(cursor).match(/^[0-9a-f]+/i); - return (_a = (m && m[0])) !== null && _a !== void 0 ? _a : ''; - } - function readHexIntegerLiteral(text, cursor) { - const prefix = text.substr(cursor, 2); - cursor += prefix.length; - if (prefix.toLowerCase() !== '0x') { - return ''; - } - const hds = readHexDigits(text, cursor); - if (hds === '') { - return ''; - } - return prefix + hds; - } - const readNonDecimalIntegerLiteral = combineReader([ - readBinaryIntegerLiteral, - readOctalIntegerLiteral, - readHexIntegerLiteral, - ]); - const readNumericLiteral = combineReader([ - readNonDecimalIntegerLiteral, - readDecimalLiteral, - ]); - - function parseLiteral(text, cursor) { - const num = readNumericLiteral(text, cursor); - cursor += num.length; - if (num === '') { - return null; - } - return { - evaluable: new NumberLiteralNode(num), - cursor: cursor, - }; - } - function parseParenthesizedExpression(text, cursor) { - const op = text.substr(cursor, 1); - cursor += op.length; - if (op !== '(') { - return null; - } - const expr = parseExpression(text, cursor); - if (!expr) { - return null; - } - cursor = expr.cursor; - cursor += readWhitespace(text, cursor).length; - const cl = text.substr(cursor, 1); - cursor += cl.length; - if (cl !== ')') { - return null; - } - return { - evaluable: expr.evaluable, - cursor: cursor, - }; - } - function parsePrimaryExpression(text, cursor) { - var _a; - return ((_a = parseLiteral(text, cursor)) !== null && _a !== void 0 ? _a : parseParenthesizedExpression(text, cursor)); - } - function parseUnaryExpression(text, cursor) { - const expr = parsePrimaryExpression(text, cursor); - if (expr) { - return expr; - } - const op = text.substr(cursor, 1); - cursor += op.length; - if (op !== '+' && op !== '-' && op !== '~') { - return null; - } - const num = parseUnaryExpression(text, cursor); - if (!num) { - return null; - } - cursor = num.cursor; - return { - cursor: cursor, - evaluable: new UnaryOperationNode(op, num.evaluable), - }; - } - function readBinaryOperator(ops, text, cursor) { - cursor += readWhitespace(text, cursor).length; - const op = ops.filter((op) => text.startsWith(op, cursor))[0]; - if (!op) { - return null; - } - cursor += op.length; - cursor += readWhitespace(text, cursor).length; - return { - cursor: cursor, - operator: op, - }; - } - function createBinaryOperationExpressionParser(exprParser, ops) { - return (text, cursor) => { - const firstExpr = exprParser(text, cursor); - if (!firstExpr) { - return null; - } - cursor = firstExpr.cursor; - let expr = firstExpr.evaluable; - for (;;) { - const op = readBinaryOperator(ops, text, cursor); - if (!op) { - break; - } - cursor = op.cursor; - const nextExpr = exprParser(text, cursor); - if (!nextExpr) { - return null; - } - cursor = nextExpr.cursor; - expr = new BinaryOperationNode(op.operator, expr, nextExpr.evaluable); - } - return expr - ? { - cursor: cursor, - evaluable: expr, - } - : null; - }; - } - const parseBinaryOperationExpression = [ - ['**'], - ['*', '/', '%'], - ['+', '-'], - ['<<', '>>>', '>>'], - ['&'], - ['^'], - ['|'], - ].reduce((parser, ops) => { - return createBinaryOperationExpressionParser(parser, ops); - }, parseUnaryExpression); - function parseExpression(text, cursor) { - cursor += readWhitespace(text, cursor).length; - return parseBinaryOperationExpression(text, cursor); - } - function parseEcmaNumberExpression(text) { - const expr = parseExpression(text, 0); - if (!expr) { - return null; - } - const cursor = expr.cursor + readWhitespace(text, expr.cursor).length; - if (cursor !== text.length) { - return null; - } - return expr.evaluable; - } - - function parseNumber(text) { - var _a; - const r = parseEcmaNumberExpression(text); - return (_a = r === null || r === void 0 ? void 0 : r.evaluate()) !== null && _a !== void 0 ? _a : null; - } - function numberFromUnknown(value) { - if (typeof value === 'number') { - return value; - } - if (typeof value === 'string') { - const pv = parseNumber(value); - if (!isEmpty(pv)) { - return pv; - } - } - return 0; - } - function createNumberFormatter(digits) { - return (value) => { - return value.toFixed(Math.max(Math.min(digits, 20), 0)); - }; - } - - function mapRange(value, start1, end1, start2, end2) { - const p = (value - start1) / (end1 - start1); - return start2 + p * (end2 - start2); - } - function getDecimalDigits(value) { - const text = String(value.toFixed(10)); - const frac = text.split('.')[1]; - return frac.replace(/0+$/, '').length; - } - function constrainRange(value, min, max) { - return Math.min(Math.max(value, min), max); - } - function loopRange(value, max) { - return ((value % max) + max) % max; - } - function getSuitableDecimalDigits(params, rawValue) { - return !isEmpty(params.step) - ? getDecimalDigits(params.step) - : Math.max(getDecimalDigits(rawValue), 2); - } - function getSuitableKeyScale(params) { - var _a; - return (_a = params.step) !== null && _a !== void 0 ? _a : 1; - } - function getSuitablePointerScale(params, rawValue) { - var _a; - const base = Math.abs((_a = params.step) !== null && _a !== void 0 ? _a : rawValue); - return base === 0 ? 0.1 : Math.pow(10, Math.floor(Math.log10(base)) - 1); - } - function createStepConstraint(params, initialValue) { - if (!isEmpty(params.step)) { - return new StepConstraint(params.step, initialValue); - } - return null; - } - function createRangeConstraint(params) { - if (!isEmpty(params.max) && !isEmpty(params.min)) { - return new DefiniteRangeConstraint({ - max: params.max, - min: params.min, - }); - } - if (!isEmpty(params.max) || !isEmpty(params.min)) { - return new RangeConstraint({ - max: params.max, - min: params.min, - }); - } - return null; - } - function createNumberTextPropsObject(params, initialValue) { - var _a, _b, _c; - return { - formatter: (_a = params.format) !== null && _a !== void 0 ? _a : createNumberFormatter(getSuitableDecimalDigits(params, initialValue)), - keyScale: (_b = params.keyScale) !== null && _b !== void 0 ? _b : getSuitableKeyScale(params), - pointerScale: (_c = params.pointerScale) !== null && _c !== void 0 ? _c : getSuitablePointerScale(params, initialValue), - }; - } - function createNumberTextInputParamsParser(p) { - return { - format: p.optional.function, - keyScale: p.optional.number, - max: p.optional.number, - min: p.optional.number, - pointerScale: p.optional.number, - step: p.optional.number, - }; - } - - function createPointAxis(config) { - return { - constraint: config.constraint, - textProps: ValueMap.fromObject(createNumberTextPropsObject(config.params, config.initialValue)), - }; - } - - class BladeApi { - constructor(controller) { - this.controller = controller; - } - get element() { - return this.controller.view.element; - } - get disabled() { - return this.controller.viewProps.get('disabled'); - } - set disabled(disabled) { - this.controller.viewProps.set('disabled', disabled); - } - get hidden() { - return this.controller.viewProps.get('hidden'); - } - set hidden(hidden) { - this.controller.viewProps.set('hidden', hidden); - } - dispose() { - this.controller.viewProps.set('disposed', true); - } - importState(state) { - return this.controller.importState(state); - } - exportState() { - return this.controller.exportState(); - } - } - - class TpEvent { - constructor(target) { - this.target = target; - } - } - class TpChangeEvent extends TpEvent { - constructor(target, value, last) { - super(target); - this.value = value; - this.last = last !== null && last !== void 0 ? last : true; - } - } - class TpFoldEvent extends TpEvent { - constructor(target, expanded) { - super(target); - this.expanded = expanded; - } - } - class TpTabSelectEvent extends TpEvent { - constructor(target, index) { - super(target); - this.index = index; - } - } - - class BindingApi extends BladeApi { - constructor(controller) { - super(controller); - this.onValueChange_ = this.onValueChange_.bind(this); - this.emitter_ = new Emitter(); - this.controller.value.emitter.on('change', this.onValueChange_); - } - get label() { - return this.controller.labelController.props.get('label'); - } - set label(label) { - this.controller.labelController.props.set('label', label); - } - get key() { - return this.controller.value.binding.target.key; - } - get tag() { - return this.controller.tag; - } - set tag(tag) { - this.controller.tag = tag; - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }); - return this; - } - refresh() { - this.controller.value.fetch(); - } - onValueChange_(ev) { - const value = this.controller.value; - this.emitter_.emit('change', new TpChangeEvent(this, forceCast(value.binding.target.read()), ev.options.last)); - } - } - - function parseObject(value, keyToParserMap) { - const keys = Object.keys(keyToParserMap); - const result = keys.reduce((tmp, key) => { - if (tmp === undefined) { - return undefined; - } - const parser = keyToParserMap[key]; - const result = parser(value[key]); - return result.succeeded - ? Object.assign(Object.assign({}, tmp), { [key]: result.value }) : undefined; - }, {}); - return forceCast(result); - } - function parseArray(value, parseItem) { - return value.reduce((tmp, item) => { - if (tmp === undefined) { - return undefined; - } - const result = parseItem(item); - if (!result.succeeded || result.value === undefined) { - return undefined; - } - return [...tmp, result.value]; - }, []); - } - function isObject(value) { - if (value === null) { - return false; - } - return typeof value === 'object'; - } - function createMicroParserBuilder(parse) { - return (optional) => (v) => { - if (!optional && v === undefined) { - return { - succeeded: false, - value: undefined, - }; - } - if (optional && v === undefined) { - return { - succeeded: true, - value: undefined, - }; - } - const result = parse(v); - return result !== undefined - ? { - succeeded: true, - value: result, - } - : { - succeeded: false, - value: undefined, - }; - }; - } - function createMicroParserBuilders(optional) { - return { - custom: (parse) => createMicroParserBuilder(parse)(optional), - boolean: createMicroParserBuilder((v) => typeof v === 'boolean' ? v : undefined)(optional), - number: createMicroParserBuilder((v) => typeof v === 'number' ? v : undefined)(optional), - string: createMicroParserBuilder((v) => typeof v === 'string' ? v : undefined)(optional), - function: createMicroParserBuilder((v) => - typeof v === 'function' ? v : undefined)(optional), - constant: (value) => createMicroParserBuilder((v) => (v === value ? value : undefined))(optional), - raw: createMicroParserBuilder((v) => v)(optional), - object: (keyToParserMap) => createMicroParserBuilder((v) => { - if (!isObject(v)) { - return undefined; - } - return parseObject(v, keyToParserMap); - })(optional), - array: (itemParser) => createMicroParserBuilder((v) => { - if (!Array.isArray(v)) { - return undefined; - } - return parseArray(v, itemParser); - })(optional), - }; - } - const MicroParsers = { - optional: createMicroParserBuilders(true), - required: createMicroParserBuilders(false), - }; - function parseRecord(value, keyToParserMap) { - const map = keyToParserMap(MicroParsers); - const result = MicroParsers.required.object(map)(value); - return result.succeeded ? result.value : undefined; - } - - function importBladeState(state, superImport, parser, callback) { - if (superImport && !superImport(state)) { - return false; - } - const result = parseRecord(state, parser); - return result ? callback(result) : false; - } - function exportBladeState(superExport, thisState) { - var _a; - return deepMerge((_a = superExport === null || superExport === void 0 ? void 0 : superExport()) !== null && _a !== void 0 ? _a : {}, thisState); - } - - function isValueBladeController(bc) { - return 'value' in bc; - } - - function isBindingValue(v) { - if (!isObject$1(v) || !('binding' in v)) { - return false; - } - const b = v.binding; - return isBinding(b); - } - - const SVG_NS = 'http://www.w3.org/2000/svg'; - function forceReflow(element) { - element.offsetHeight; - } - function disableTransitionTemporarily(element, callback) { - const t = element.style.transition; - element.style.transition = 'none'; - callback(); - element.style.transition = t; - } - function supportsTouch(doc) { - return doc.ontouchstart !== undefined; - } - function getCanvasContext(canvasElement) { - const win = canvasElement.ownerDocument.defaultView; - if (!win) { - return null; - } - const isBrowser = 'document' in win; - return isBrowser - ? canvasElement.getContext('2d', { - willReadFrequently: true, - }) - : null; - } - const ICON_ID_TO_INNER_HTML_MAP = { - check: '', - dropdown: '', - p2dpad: '', - }; - function createSvgIconElement(document, iconId) { - const elem = document.createElementNS(SVG_NS, 'svg'); - elem.innerHTML = ICON_ID_TO_INNER_HTML_MAP[iconId]; - return elem; - } - function insertElementAt(parentElement, element, index) { - parentElement.insertBefore(element, parentElement.children[index]); - } - function removeElement(element) { - if (element.parentElement) { - element.parentElement.removeChild(element); - } - } - function removeChildElements(element) { - while (element.children.length > 0) { - element.removeChild(element.children[0]); - } - } - function removeChildNodes(element) { - while (element.childNodes.length > 0) { - element.removeChild(element.childNodes[0]); - } - } - function findNextTarget(ev) { - if (ev.relatedTarget) { - return forceCast(ev.relatedTarget); - } - if ('explicitOriginalTarget' in ev) { - return ev.explicitOriginalTarget; - } - return null; - } - - function bindValue(value, applyValue) { - value.emitter.on('change', (ev) => { - applyValue(ev.rawValue); - }); - applyValue(value.rawValue); - } - function bindValueMap(valueMap, key, applyValue) { - bindValue(valueMap.value(key), applyValue); - } - - const PREFIX = 'tp'; - function ClassName(viewName) { - const fn = (opt_elementName, opt_modifier) => { - return [ - PREFIX, - '-', - viewName, - 'v', - opt_elementName ? `_${opt_elementName}` : '', - opt_modifier ? `-${opt_modifier}` : '', - ].join(''); - }; - return fn; - } - - const cn$q = ClassName('lbl'); - function createLabelNode(doc, label) { - const frag = doc.createDocumentFragment(); - const lineNodes = label.split('\n').map((line) => { - return doc.createTextNode(line); - }); - lineNodes.forEach((lineNode, index) => { - if (index > 0) { - frag.appendChild(doc.createElement('br')); - } - frag.appendChild(lineNode); - }); - return frag; - } - class LabelView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$q()); - config.viewProps.bindClassModifiers(this.element); - const labelElem = doc.createElement('div'); - labelElem.classList.add(cn$q('l')); - bindValueMap(config.props, 'label', (value) => { - if (isEmpty(value)) { - this.element.classList.add(cn$q(undefined, 'nol')); - } - else { - this.element.classList.remove(cn$q(undefined, 'nol')); - removeChildNodes(labelElem); - labelElem.appendChild(createLabelNode(doc, value)); - } - }); - this.element.appendChild(labelElem); - this.labelElement = labelElem; - const valueElem = doc.createElement('div'); - valueElem.classList.add(cn$q('v')); - this.element.appendChild(valueElem); - this.valueElement = valueElem; - } - } - - class LabelController { - constructor(doc, config) { - this.props = config.props; - this.valueController = config.valueController; - this.viewProps = config.valueController.viewProps; - this.view = new LabelView(doc, { - props: config.props, - viewProps: this.viewProps, - }); - this.view.valueElement.appendChild(this.valueController.view.element); - } - importProps(state) { - return importBladeState(state, null, (p) => ({ - label: p.optional.string, - }), (result) => { - this.props.set('label', result.label); - return true; - }); - } - exportProps() { - return exportBladeState(null, { - label: this.props.get('label'), - }); - } - } - - function getAllBladePositions() { - return ['veryfirst', 'first', 'last', 'verylast']; - } - - const cn$p = ClassName(''); - const POS_TO_CLASS_NAME_MAP = { - veryfirst: 'vfst', - first: 'fst', - last: 'lst', - verylast: 'vlst', - }; - class BladeController { - constructor(config) { - this.parent_ = null; - this.blade = config.blade; - this.view = config.view; - this.viewProps = config.viewProps; - const elem = this.view.element; - this.blade.value('positions').emitter.on('change', () => { - getAllBladePositions().forEach((pos) => { - elem.classList.remove(cn$p(undefined, POS_TO_CLASS_NAME_MAP[pos])); - }); - this.blade.get('positions').forEach((pos) => { - elem.classList.add(cn$p(undefined, POS_TO_CLASS_NAME_MAP[pos])); - }); - }); - this.viewProps.handleDispose(() => { - removeElement(elem); - }); - } - get parent() { - return this.parent_; - } - set parent(parent) { - this.parent_ = parent; - this.viewProps.set('parent', this.parent_ ? this.parent_.viewProps : null); - } - importState(state) { - return importBladeState(state, null, (p) => ({ - disabled: p.required.boolean, - hidden: p.required.boolean, - }), (result) => { - this.viewProps.importState(result); - return true; - }); - } - exportState() { - return exportBladeState(null, Object.assign({}, this.viewProps.exportState())); - } - } - - class LabeledValueBladeController extends BladeController { - constructor(doc, config) { - if (config.value !== config.valueController.value) { - throw TpError.shouldNeverHappen(); - } - const viewProps = config.valueController.viewProps; - const lc = new LabelController(doc, { - blade: config.blade, - props: config.props, - valueController: config.valueController, - }); - super(Object.assign(Object.assign({}, config), { view: new LabelView(doc, { - props: config.props, - viewProps: viewProps, - }), viewProps: viewProps })); - this.labelController = lc; - this.value = config.value; - this.valueController = config.valueController; - this.view.valueElement.appendChild(this.valueController.view.element); - } - importState(state) { - return importBladeState(state, (s) => { - var _a, _b, _c; - return super.importState(s) && - this.labelController.importProps(s) && - ((_c = (_b = (_a = this.valueController).importProps) === null || _b === void 0 ? void 0 : _b.call(_a, state)) !== null && _c !== void 0 ? _c : true); - }, (p) => ({ - value: p.optional.raw, - }), (result) => { - if (result.value) { - this.value.rawValue = result.value; - } - return true; - }); - } - exportState() { - var _a, _b, _c; - return exportBladeState(() => super.exportState(), Object.assign(Object.assign({ value: this.value.rawValue }, this.labelController.exportProps()), ((_c = (_b = (_a = this.valueController).exportProps) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : {}))); - } - } - - function fillBuffer(buffer, bufferSize) { - while (buffer.length < bufferSize) { - buffer.push(undefined); - } - } - function initializeBuffer(bufferSize) { - const buffer = []; - fillBuffer(buffer, bufferSize); - return buffer; - } - function createTrimmedBuffer(buffer) { - const index = buffer.indexOf(undefined); - return forceCast(index < 0 ? buffer : buffer.slice(0, index)); - } - function createPushedBuffer(buffer, newValue) { - const newBuffer = [...createTrimmedBuffer(buffer), newValue]; - if (newBuffer.length > buffer.length) { - newBuffer.splice(0, newBuffer.length - buffer.length); - } - else { - fillBuffer(newBuffer, buffer.length); - } - return newBuffer; - } - - class ButtonApi extends BladeApi { - get label() { - return this.controller.labelController.props.get('label'); - } - set label(label) { - this.controller.labelController.props.set('label', label); - } - get title() { - var _a; - return (_a = this.controller.buttonController.props.get('title')) !== null && _a !== void 0 ? _a : ''; - } - set title(title) { - this.controller.buttonController.props.set('title', title); - } - on(eventName, handler) { - const bh = handler.bind(this); - const emitter = this.controller.buttonController.emitter; - emitter.on(eventName, () => { - bh(new TpEvent(this)); - }); - return this; - } - } - - function applyClass(elem, className, active) { - if (active) { - elem.classList.add(className); - } - else { - elem.classList.remove(className); - } - } - function valueToClassName(elem, className) { - return (value) => { - applyClass(elem, className, value); - }; - } - function bindValueToTextContent(value, elem) { - bindValue(value, (text) => { - elem.textContent = text !== null && text !== void 0 ? text : ''; - }); - } - - const cn$o = ClassName('btn'); - class ButtonView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$o()); - config.viewProps.bindClassModifiers(this.element); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(cn$o('b')); - config.viewProps.bindDisabled(buttonElem); - this.element.appendChild(buttonElem); - this.buttonElement = buttonElem; - const titleElem = doc.createElement('div'); - titleElem.classList.add(cn$o('t')); - bindValueToTextContent(config.props.value('title'), titleElem); - this.buttonElement.appendChild(titleElem); - } - } - - class ButtonController { - constructor(doc, config) { - this.emitter = new Emitter(); - this.onClick_ = this.onClick_.bind(this); - this.props = config.props; - this.viewProps = config.viewProps; - this.view = new ButtonView(doc, { - props: this.props, - viewProps: this.viewProps, - }); - this.view.buttonElement.addEventListener('click', this.onClick_); - } - importProps(state) { - return importBladeState(state, null, (p) => ({ - title: p.optional.string, - }), (result) => { - this.props.set('title', result.title); - return true; - }); - } - exportProps() { - return exportBladeState(null, { - title: this.props.get('title'), - }); - } - onClick_() { - this.emitter.emit('click', { - sender: this, - }); - } - } - - class ButtonBladeController extends BladeController { - constructor(doc, config) { - const bc = new ButtonController(doc, { - props: config.buttonProps, - viewProps: config.viewProps, - }); - const lc = new LabelController(doc, { - blade: config.blade, - props: config.labelProps, - valueController: bc, - }); - super({ - blade: config.blade, - view: lc.view, - viewProps: config.viewProps, - }); - this.buttonController = bc; - this.labelController = lc; - } - importState(state) { - return importBladeState(state, (s) => super.importState(s) && - this.buttonController.importProps(s) && - this.labelController.importProps(s), () => ({}), () => true); - } - exportState() { - return exportBladeState(() => super.exportState(), Object.assign(Object.assign({}, this.buttonController.exportProps()), this.labelController.exportProps())); - } - } - - class Semver { - constructor(text) { - const [core, prerelease] = text.split('-'); - const coreComps = core.split('.'); - this.major = parseInt(coreComps[0], 10); - this.minor = parseInt(coreComps[1], 10); - this.patch = parseInt(coreComps[2], 10); - this.prerelease = prerelease !== null && prerelease !== void 0 ? prerelease : null; - } - toString() { - const core = [this.major, this.minor, this.patch].join('.'); - return this.prerelease !== null ? [core, this.prerelease].join('-') : core; - } - } - - const VERSION = new Semver('2.0.0-beta.2'); - - function createPlugin(plugin) { - return Object.assign({ core: VERSION }, plugin); - } - - createPlugin({ - id: 'button', - type: 'blade', - accept(params) { - const result = parseRecord(params, (p) => ({ - title: p.required.string, - view: p.required.constant('button'), - label: p.optional.string, - })); - return result ? { params: result } : null; - }, - controller(args) { - return new ButtonBladeController(args.document, { - blade: args.blade, - buttonProps: ValueMap.fromObject({ - title: args.params.title, - }), - labelProps: ValueMap.fromObject({ - label: args.params.label, - }), - viewProps: args.viewProps, - }); - }, - api(args) { - if (args.controller instanceof ButtonBladeController) { - return new ButtonApi(args.controller); - } - return null; - }, - }); - - function addButtonAsBlade(api, params) { - return api.addBlade(Object.assign(Object.assign({}, params), { view: 'button' })); - } - function addFolderAsBlade(api, params) { - return api.addBlade(Object.assign(Object.assign({}, params), { view: 'folder' })); - } - function addTabAsBlade(api, params) { - return api.addBlade(Object.assign(Object.assign({}, params), { view: 'tab' })); - } - - function isRefreshable(value) { - if (!isObject$1(value)) { - return false; - } - return 'refresh' in value && typeof value.refresh === 'function'; - } - - function createBindingTarget(obj, key) { - if (!BindingTarget.isBindable(obj)) { - throw TpError.notBindable(); - } - return new BindingTarget(obj, key); - } - class RackApi { - constructor(controller, pool) { - this.onRackValueChange_ = this.onRackValueChange_.bind(this); - this.controller_ = controller; - this.emitter_ = new Emitter(); - this.pool_ = pool; - const rack = this.controller_.rack; - rack.emitter.on('valuechange', this.onRackValueChange_); - } - get children() { - return this.controller_.rack.children.map((bc) => this.pool_.createApi(bc)); - } - addBinding(object, key, opt_params) { - const params = opt_params !== null && opt_params !== void 0 ? opt_params : {}; - const doc = this.controller_.element.ownerDocument; - const bc = this.pool_.createBinding(doc, createBindingTarget(object, key), params); - const api = this.pool_.createBindingApi(bc); - return this.add(api, params.index); - } - addFolder(params) { - return addFolderAsBlade(this, params); - } - addButton(params) { - return addButtonAsBlade(this, params); - } - addTab(params) { - return addTabAsBlade(this, params); - } - add(api, opt_index) { - const bc = api.controller; - this.controller_.rack.add(bc, opt_index); - return api; - } - remove(api) { - this.controller_.rack.remove(api.controller); - } - addBlade(params) { - const doc = this.controller_.element.ownerDocument; - const bc = this.pool_.createBlade(doc, params); - const api = this.pool_.createApi(bc); - return this.add(api, params.index); - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }); - return this; - } - refresh() { - this.children.forEach((c) => { - if (isRefreshable(c)) { - c.refresh(); - } - }); - } - onRackValueChange_(ev) { - const bc = ev.bladeController; - const api = this.pool_.createApi(bc); - const binding = isBindingValue(bc.value) ? bc.value.binding : null; - this.emitter_.emit('change', new TpChangeEvent(api, binding ? binding.target.read() : bc.value.rawValue, ev.options.last)); - } - } - - class ContainerBladeApi extends BladeApi { - constructor(controller, pool) { - super(controller); - this.rackApi_ = new RackApi(controller.rackController, pool); - } - } - - class ContainerBladeController extends BladeController { - constructor(config) { - super({ - blade: config.blade, - view: config.view, - viewProps: config.rackController.viewProps, - }); - this.rackController = config.rackController; - } - importState(state) { - return importBladeState(state, (s) => super.importState(s), (p) => ({ - children: p.required.array(p.required.raw), - }), (result) => { - return this.rackController.rack.children.every((c, index) => { - return c.importState(result.children[index]); - }); - }); - } - exportState() { - return exportBladeState(() => super.exportState(), { - children: this.rackController.rack.children.map((c) => c.exportState()), - }); - } - } - function isContainerBladeController(bc) { - return 'rackController' in bc; - } - - class NestedOrderedSet { - constructor(extract) { - this.emitter = new Emitter(); - this.items_ = []; - this.cache_ = new Set(); - this.onSubListAdd_ = this.onSubListAdd_.bind(this); - this.onSubListRemove_ = this.onSubListRemove_.bind(this); - this.extract_ = extract; - } - get items() { - return this.items_; - } - allItems() { - return Array.from(this.cache_); - } - find(callback) { - for (const item of this.allItems()) { - if (callback(item)) { - return item; - } - } - return null; - } - includes(item) { - return this.cache_.has(item); - } - add(item, opt_index) { - if (this.includes(item)) { - throw TpError.shouldNeverHappen(); - } - const index = opt_index !== undefined ? opt_index : this.items_.length; - this.items_.splice(index, 0, item); - this.cache_.add(item); - const subList = this.extract_(item); - if (subList) { - subList.emitter.on('add', this.onSubListAdd_); - subList.emitter.on('remove', this.onSubListRemove_); - subList.allItems().forEach((i) => { - this.cache_.add(i); - }); - } - this.emitter.emit('add', { - index: index, - item: item, - root: this, - target: this, - }); - } - remove(item) { - const index = this.items_.indexOf(item); - if (index < 0) { - return; - } - this.items_.splice(index, 1); - this.cache_.delete(item); - const subList = this.extract_(item); - if (subList) { - subList.allItems().forEach((i) => { - this.cache_.delete(i); - }); - subList.emitter.off('add', this.onSubListAdd_); - subList.emitter.off('remove', this.onSubListRemove_); - } - this.emitter.emit('remove', { - index: index, - item: item, - root: this, - target: this, - }); - } - onSubListAdd_(ev) { - this.cache_.add(ev.item); - this.emitter.emit('add', { - index: ev.index, - item: ev.item, - root: this, - target: ev.target, - }); - } - onSubListRemove_(ev) { - this.cache_.delete(ev.item); - this.emitter.emit('remove', { - index: ev.index, - item: ev.item, - root: this, - target: ev.target, - }); - } - } - - function findValueBladeController(bcs, v) { - for (let i = 0; i < bcs.length; i++) { - const bc = bcs[i]; - if (isValueBladeController(bc) && bc.value === v) { - return bc; - } - } - return null; - } - function findSubBladeControllerSet(bc) { - return isContainerBladeController(bc) - ? bc.rackController.rack['bcSet_'] - : null; - } - class Rack { - constructor(config) { - var _a, _b; - this.emitter = new Emitter(); - this.onBladePositionsChange_ = this.onBladePositionsChange_.bind(this); - this.onSetAdd_ = this.onSetAdd_.bind(this); - this.onSetRemove_ = this.onSetRemove_.bind(this); - this.onChildDispose_ = this.onChildDispose_.bind(this); - this.onChildPositionsChange_ = this.onChildPositionsChange_.bind(this); - this.onChildValueChange_ = this.onChildValueChange_.bind(this); - this.onChildViewPropsChange_ = this.onChildViewPropsChange_.bind(this); - this.onRackLayout_ = this.onRackLayout_.bind(this); - this.onRackValueChange_ = this.onRackValueChange_.bind(this); - this.blade_ = (_a = config.blade) !== null && _a !== void 0 ? _a : null; - (_b = this.blade_) === null || _b === void 0 ? void 0 : _b.value('positions').emitter.on('change', this.onBladePositionsChange_); - this.viewProps = config.viewProps; - this.bcSet_ = new NestedOrderedSet(findSubBladeControllerSet); - this.bcSet_.emitter.on('add', this.onSetAdd_); - this.bcSet_.emitter.on('remove', this.onSetRemove_); - } - get children() { - return this.bcSet_.items; - } - add(bc, opt_index) { - var _a; - (_a = bc.parent) === null || _a === void 0 ? void 0 : _a.remove(bc); - bc.parent = this; - this.bcSet_.add(bc, opt_index); - } - remove(bc) { - bc.parent = null; - this.bcSet_.remove(bc); - } - find(finder) { - return this.bcSet_.allItems().filter(finder); - } - onSetAdd_(ev) { - this.updatePositions_(); - const root = ev.target === ev.root; - this.emitter.emit('add', { - bladeController: ev.item, - index: ev.index, - root: root, - sender: this, - }); - if (!root) { - return; - } - const bc = ev.item; - bc.viewProps.emitter.on('change', this.onChildViewPropsChange_); - bc.blade - .value('positions') - .emitter.on('change', this.onChildPositionsChange_); - bc.viewProps.handleDispose(this.onChildDispose_); - if (isValueBladeController(bc)) { - bc.value.emitter.on('change', this.onChildValueChange_); - } - else if (isContainerBladeController(bc)) { - const rack = bc.rackController.rack; - if (rack) { - const emitter = rack.emitter; - emitter.on('layout', this.onRackLayout_); - emitter.on('valuechange', this.onRackValueChange_); - } - } - } - onSetRemove_(ev) { - this.updatePositions_(); - const root = ev.target === ev.root; - this.emitter.emit('remove', { - bladeController: ev.item, - root: root, - sender: this, - }); - if (!root) { - return; - } - const bc = ev.item; - if (isValueBladeController(bc)) { - bc.value.emitter.off('change', this.onChildValueChange_); - } - else if (isContainerBladeController(bc)) { - const rack = bc.rackController.rack; - if (rack) { - const emitter = rack.emitter; - emitter.off('layout', this.onRackLayout_); - emitter.off('valuechange', this.onRackValueChange_); - } - } - } - updatePositions_() { - const visibleItems = this.bcSet_.items.filter((bc) => !bc.viewProps.get('hidden')); - const firstVisibleItem = visibleItems[0]; - const lastVisibleItem = visibleItems[visibleItems.length - 1]; - this.bcSet_.items.forEach((bc) => { - const ps = []; - if (bc === firstVisibleItem) { - ps.push('first'); - if (!this.blade_ || - this.blade_.get('positions').includes('veryfirst')) { - ps.push('veryfirst'); - } - } - if (bc === lastVisibleItem) { - ps.push('last'); - if (!this.blade_ || this.blade_.get('positions').includes('verylast')) { - ps.push('verylast'); - } - } - bc.blade.set('positions', ps); - }); - } - onChildPositionsChange_() { - this.updatePositions_(); - this.emitter.emit('layout', { - sender: this, - }); - } - onChildViewPropsChange_(_ev) { - this.updatePositions_(); - this.emitter.emit('layout', { - sender: this, - }); - } - onChildDispose_() { - const disposedUcs = this.bcSet_.items.filter((bc) => { - return bc.viewProps.get('disposed'); - }); - disposedUcs.forEach((bc) => { - this.bcSet_.remove(bc); - }); - } - onChildValueChange_(ev) { - const bc = findValueBladeController(this.find(isValueBladeController), ev.sender); - if (!bc) { - throw TpError.alreadyDisposed(); - } - this.emitter.emit('valuechange', { - bladeController: bc, - options: ev.options, - sender: this, - }); - } - onRackLayout_(_) { - this.updatePositions_(); - this.emitter.emit('layout', { - sender: this, - }); - } - onRackValueChange_(ev) { - this.emitter.emit('valuechange', { - bladeController: ev.bladeController, - options: ev.options, - sender: this, - }); - } - onBladePositionsChange_() { - this.updatePositions_(); - } - } - - class RackController { - constructor(config) { - this.onRackAdd_ = this.onRackAdd_.bind(this); - this.onRackRemove_ = this.onRackRemove_.bind(this); - this.element = config.element; - this.viewProps = config.viewProps; - const rack = new Rack({ - blade: config.root ? undefined : config.blade, - viewProps: config.viewProps, - }); - rack.emitter.on('add', this.onRackAdd_); - rack.emitter.on('remove', this.onRackRemove_); - this.rack = rack; - this.viewProps.handleDispose(() => { - for (let i = this.rack.children.length - 1; i >= 0; i--) { - const bc = this.rack.children[i]; - bc.viewProps.set('disposed', true); - } - }); - } - onRackAdd_(ev) { - if (!ev.root) { - return; - } - insertElementAt(this.element, ev.bladeController.view.element, ev.index); - } - onRackRemove_(ev) { - if (!ev.root) { - return; - } - removeElement(ev.bladeController.view.element); - } - } - - function createBlade() { - return new ValueMap({ - positions: createValue([], { - equals: deepEqualsArray, - }), - }); - } - - class Foldable extends ValueMap { - constructor(valueMap) { - super(valueMap); - } - static create(expanded) { - const coreObj = { - completed: true, - expanded: expanded, - expandedHeight: null, - shouldFixHeight: false, - temporaryExpanded: null, - }; - const core = ValueMap.createCore(coreObj); - return new Foldable(core); - } - get styleExpanded() { - var _a; - return (_a = this.get('temporaryExpanded')) !== null && _a !== void 0 ? _a : this.get('expanded'); - } - get styleHeight() { - if (!this.styleExpanded) { - return '0'; - } - const exHeight = this.get('expandedHeight'); - if (this.get('shouldFixHeight') && !isEmpty(exHeight)) { - return `${exHeight}px`; - } - return 'auto'; - } - bindExpandedClass(elem, expandedClassName) { - const onExpand = () => { - const expanded = this.styleExpanded; - if (expanded) { - elem.classList.add(expandedClassName); - } - else { - elem.classList.remove(expandedClassName); - } - }; - bindValueMap(this, 'expanded', onExpand); - bindValueMap(this, 'temporaryExpanded', onExpand); - } - cleanUpTransition() { - this.set('shouldFixHeight', false); - this.set('expandedHeight', null); - this.set('completed', true); - } - } - function computeExpandedFolderHeight(folder, containerElement) { - let height = 0; - disableTransitionTemporarily(containerElement, () => { - folder.set('expandedHeight', null); - folder.set('temporaryExpanded', true); - forceReflow(containerElement); - height = containerElement.clientHeight; - folder.set('temporaryExpanded', null); - forceReflow(containerElement); - }); - return height; - } - function applyHeight(foldable, elem) { - elem.style.height = foldable.styleHeight; - } - function bindFoldable(foldable, elem) { - foldable.value('expanded').emitter.on('beforechange', () => { - foldable.set('completed', false); - if (isEmpty(foldable.get('expandedHeight'))) { - const h = computeExpandedFolderHeight(foldable, elem); - if (h > 0) { - foldable.set('expandedHeight', h); - } - } - foldable.set('shouldFixHeight', true); - forceReflow(elem); - }); - foldable.emitter.on('change', () => { - applyHeight(foldable, elem); - }); - applyHeight(foldable, elem); - elem.addEventListener('transitionend', (ev) => { - if (ev.propertyName !== 'height') { - return; - } - foldable.cleanUpTransition(); - }); - } - - class FolderApi extends ContainerBladeApi { - constructor(controller, pool) { - super(controller, pool); - this.emitter_ = new Emitter(); - this.controller.foldable - .value('expanded') - .emitter.on('change', (ev) => { - this.emitter_.emit('fold', new TpFoldEvent(this, ev.sender.rawValue)); - }); - this.rackApi_.on('change', (ev) => { - this.emitter_.emit('change', ev); - }); - } - get expanded() { - return this.controller.foldable.get('expanded'); - } - set expanded(expanded) { - this.controller.foldable.set('expanded', expanded); - } - get title() { - return this.controller.props.get('title'); - } - set title(title) { - this.controller.props.set('title', title); - } - get children() { - return this.rackApi_.children; - } - addBinding(object, key, opt_params) { - return this.rackApi_.addBinding(object, key, opt_params); - } - addFolder(params) { - return this.rackApi_.addFolder(params); - } - addButton(params) { - return this.rackApi_.addButton(params); - } - addTab(params) { - return this.rackApi_.addTab(params); - } - add(api, opt_index) { - return this.rackApi_.add(api, opt_index); - } - remove(api) { - this.rackApi_.remove(api); - } - addBlade(params) { - return this.rackApi_.addBlade(params); - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }); - return this; - } - refresh() { - this.rackApi_.refresh(); - } - } - - const bladeContainerClassName = ClassName('cnt'); - - class FolderView { - constructor(doc, config) { - var _a; - this.className_ = ClassName((_a = config.viewName) !== null && _a !== void 0 ? _a : 'fld'); - this.element = doc.createElement('div'); - this.element.classList.add(this.className_(), bladeContainerClassName()); - config.viewProps.bindClassModifiers(this.element); - this.foldable_ = config.foldable; - this.foldable_.bindExpandedClass(this.element, this.className_(undefined, 'expanded')); - bindValueMap(this.foldable_, 'completed', valueToClassName(this.element, this.className_(undefined, 'cpl'))); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(this.className_('b')); - bindValueMap(config.props, 'title', (title) => { - if (isEmpty(title)) { - this.element.classList.add(this.className_(undefined, 'not')); - } - else { - this.element.classList.remove(this.className_(undefined, 'not')); - } - }); - config.viewProps.bindDisabled(buttonElem); - this.element.appendChild(buttonElem); - this.buttonElement = buttonElem; - const indentElem = doc.createElement('div'); - indentElem.classList.add(this.className_('i')); - this.element.appendChild(indentElem); - const titleElem = doc.createElement('div'); - titleElem.classList.add(this.className_('t')); - bindValueToTextContent(config.props.value('title'), titleElem); - this.buttonElement.appendChild(titleElem); - this.titleElement = titleElem; - const markElem = doc.createElement('div'); - markElem.classList.add(this.className_('m')); - this.buttonElement.appendChild(markElem); - const containerElem = doc.createElement('div'); - containerElem.classList.add(this.className_('c')); - this.element.appendChild(containerElem); - this.containerElement = containerElem; - } - } - - class FolderController extends ContainerBladeController { - constructor(doc, config) { - var _a; - const foldable = Foldable.create((_a = config.expanded) !== null && _a !== void 0 ? _a : true); - const view = new FolderView(doc, { - foldable: foldable, - props: config.props, - viewName: config.root ? 'rot' : undefined, - viewProps: config.viewProps, - }); - super(Object.assign(Object.assign({}, config), { rackController: new RackController({ - blade: config.blade, - element: view.containerElement, - root: config.root, - viewProps: config.viewProps, - }), view: view })); - this.onTitleClick_ = this.onTitleClick_.bind(this); - this.props = config.props; - this.foldable = foldable; - bindFoldable(this.foldable, this.view.containerElement); - this.rackController.rack.emitter.on('add', () => { - this.foldable.cleanUpTransition(); - }); - this.rackController.rack.emitter.on('remove', () => { - this.foldable.cleanUpTransition(); - }); - this.view.buttonElement.addEventListener('click', this.onTitleClick_); - } - get document() { - return this.view.element.ownerDocument; - } - importState(state) { - return importBladeState(state, (s) => super.importState(s), (p) => ({ - expanded: p.required.boolean, - title: p.optional.string, - }), (result) => { - this.foldable.set('expanded', result.expanded); - this.props.set('title', result.title); - return true; - }); - } - exportState() { - return exportBladeState(() => super.exportState(), { - expanded: this.foldable.get('expanded'), - title: this.props.get('title'), - }); - } - onTitleClick_() { - this.foldable.set('expanded', !this.foldable.get('expanded')); - } - } - - createPlugin({ - id: 'folder', - type: 'blade', - accept(params) { - const result = parseRecord(params, (p) => ({ - title: p.required.string, - view: p.required.constant('folder'), - expanded: p.optional.boolean, - })); - return result ? { params: result } : null; - }, - controller(args) { - return new FolderController(args.document, { - blade: args.blade, - expanded: args.params.expanded, - props: ValueMap.fromObject({ - title: args.params.title, - }), - viewProps: args.viewProps, - }); - }, - api(args) { - if (!(args.controller instanceof FolderController)) { - return null; - } - return new FolderApi(args.controller, args.pool); - }, - }); - - const cn$n = ClassName(''); - function valueToModifier(elem, modifier) { - return valueToClassName(elem, cn$n(undefined, modifier)); - } - class ViewProps extends ValueMap { - constructor(valueMap) { - var _a; - super(valueMap); - this.onDisabledChange_ = this.onDisabledChange_.bind(this); - this.onParentChange_ = this.onParentChange_.bind(this); - this.onParentGlobalDisabledChange_ = - this.onParentGlobalDisabledChange_.bind(this); - [this.globalDisabled_, this.setGlobalDisabled_] = createReadonlyValue(createValue(this.getGlobalDisabled_())); - this.value('disabled').emitter.on('change', this.onDisabledChange_); - this.value('parent').emitter.on('change', this.onParentChange_); - (_a = this.get('parent')) === null || _a === void 0 ? void 0 : _a.globalDisabled.emitter.on('change', this.onParentGlobalDisabledChange_); - } - static create(opt_initialValue) { - var _a, _b, _c; - const initialValue = opt_initialValue !== null && opt_initialValue !== void 0 ? opt_initialValue : {}; - return new ViewProps(ValueMap.createCore({ - disabled: (_a = initialValue.disabled) !== null && _a !== void 0 ? _a : false, - disposed: false, - hidden: (_b = initialValue.hidden) !== null && _b !== void 0 ? _b : false, - parent: (_c = initialValue.parent) !== null && _c !== void 0 ? _c : null, - })); - } - get globalDisabled() { - return this.globalDisabled_; - } - bindClassModifiers(elem) { - bindValue(this.globalDisabled_, valueToModifier(elem, 'disabled')); - bindValueMap(this, 'hidden', valueToModifier(elem, 'hidden')); - } - bindDisabled(target) { - bindValue(this.globalDisabled_, (disabled) => { - target.disabled = disabled; - }); - } - bindTabIndex(elem) { - bindValue(this.globalDisabled_, (disabled) => { - elem.tabIndex = disabled ? -1 : 0; - }); - } - handleDispose(callback) { - this.value('disposed').emitter.on('change', (disposed) => { - if (disposed) { - callback(); - } - }); - } - importState(state) { - this.set('disabled', state.disabled); - this.set('hidden', state.hidden); - } - exportState() { - return { - disabled: this.get('disabled'), - hidden: this.get('hidden'), - }; - } - getGlobalDisabled_() { - const parent = this.get('parent'); - const parentDisabled = parent ? parent.globalDisabled.rawValue : false; - return parentDisabled || this.get('disabled'); - } - updateGlobalDisabled_() { - this.setGlobalDisabled_(this.getGlobalDisabled_()); - } - onDisabledChange_() { - this.updateGlobalDisabled_(); - } - onParentGlobalDisabledChange_() { - this.updateGlobalDisabled_(); - } - onParentChange_(ev) { - var _a; - const prevParent = ev.previousRawValue; - prevParent === null || prevParent === void 0 ? void 0 : prevParent.globalDisabled.emitter.off('change', this.onParentGlobalDisabledChange_); - (_a = this.get('parent')) === null || _a === void 0 ? void 0 : _a.globalDisabled.emitter.on('change', this.onParentGlobalDisabledChange_); - this.updateGlobalDisabled_(); - } - } - - const cn$m = ClassName('tbp'); - class TabPageView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$m()); - config.viewProps.bindClassModifiers(this.element); - const containerElem = doc.createElement('div'); - containerElem.classList.add(cn$m('c')); - this.element.appendChild(containerElem); - this.containerElement = containerElem; - } - } - - const cn$l = ClassName('tbi'); - class TabItemView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$l()); - config.viewProps.bindClassModifiers(this.element); - bindValueMap(config.props, 'selected', (selected) => { - if (selected) { - this.element.classList.add(cn$l(undefined, 'sel')); - } - else { - this.element.classList.remove(cn$l(undefined, 'sel')); - } - }); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(cn$l('b')); - config.viewProps.bindDisabled(buttonElem); - this.element.appendChild(buttonElem); - this.buttonElement = buttonElem; - const titleElem = doc.createElement('div'); - titleElem.classList.add(cn$l('t')); - bindValueToTextContent(config.props.value('title'), titleElem); - this.buttonElement.appendChild(titleElem); - this.titleElement = titleElem; - } - } - - class TabItemController { - constructor(doc, config) { - this.emitter = new Emitter(); - this.onClick_ = this.onClick_.bind(this); - this.props = config.props; - this.viewProps = config.viewProps; - this.view = new TabItemView(doc, { - props: config.props, - viewProps: config.viewProps, - }); - this.view.buttonElement.addEventListener('click', this.onClick_); - } - onClick_() { - this.emitter.emit('click', { - sender: this, - }); - } - } - - class TabPageController extends ContainerBladeController { - constructor(doc, config) { - const view = new TabPageView(doc, { - viewProps: config.viewProps, - }); - super(Object.assign(Object.assign({}, config), { rackController: new RackController({ - blade: config.blade, - element: view.containerElement, - viewProps: config.viewProps, - }), view: view })); - this.onItemClick_ = this.onItemClick_.bind(this); - this.ic_ = new TabItemController(doc, { - props: config.itemProps, - viewProps: ViewProps.create(), - }); - this.ic_.emitter.on('click', this.onItemClick_); - this.props = config.props; - bindValueMap(this.props, 'selected', (selected) => { - this.itemController.props.set('selected', selected); - this.viewProps.set('hidden', !selected); - }); - } - get itemController() { - return this.ic_; - } - importState(state) { - return importBladeState(state, (s) => super.importState(s), (p) => ({ - selected: p.required.boolean, - title: p.required.string, - }), (result) => { - this.ic_.props.set('selected', result.selected); - this.ic_.props.set('title', result.title); - return true; - }); - } - exportState() { - return exportBladeState(() => super.exportState(), { - selected: this.ic_.props.get('selected'), - title: this.ic_.props.get('title'), - }); - } - onItemClick_() { - this.props.set('selected', true); - } - } - - class TabApi extends ContainerBladeApi { - constructor(controller, pool) { - super(controller, pool); - this.emitter_ = new Emitter(); - this.onSelect_ = this.onSelect_.bind(this); - this.pool_ = pool; - this.rackApi_.on('change', (ev) => { - this.emitter_.emit('change', ev); - }); - this.controller.tab.selectedIndex.emitter.on('change', this.onSelect_); - } - get pages() { - return this.rackApi_.children; - } - addPage(params) { - const doc = this.controller.view.element.ownerDocument; - const pc = new TabPageController(doc, { - blade: createBlade(), - itemProps: ValueMap.fromObject({ - selected: false, - title: params.title, - }), - props: ValueMap.fromObject({ - selected: false, - }), - viewProps: ViewProps.create(), - }); - const papi = this.pool_.createApi(pc); - return this.rackApi_.add(papi, params.index); - } - removePage(index) { - this.rackApi_.remove(this.rackApi_.children[index]); - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev); - }); - return this; - } - onSelect_(ev) { - this.emitter_.emit('select', new TpTabSelectEvent(this, ev.rawValue)); - } - } - - class TabPageApi extends ContainerBladeApi { - get title() { - var _a; - return (_a = this.controller.itemController.props.get('title')) !== null && _a !== void 0 ? _a : ''; - } - set title(title) { - this.controller.itemController.props.set('title', title); - } - get selected() { - return this.controller.props.get('selected'); - } - set selected(selected) { - this.controller.props.set('selected', selected); - } - get children() { - return this.rackApi_.children; - } - addButton(params) { - return this.rackApi_.addButton(params); - } - addFolder(params) { - return this.rackApi_.addFolder(params); - } - addTab(params) { - return this.rackApi_.addTab(params); - } - add(api, opt_index) { - this.rackApi_.add(api, opt_index); - } - remove(api) { - this.rackApi_.remove(api); - } - addBinding(object, key, opt_params) { - return this.rackApi_.addBinding(object, key, opt_params); - } - addBlade(params) { - return this.rackApi_.addBlade(params); - } - refresh() { - this.rackApi_.refresh(); - } - } - - const INDEX_NOT_SELECTED = -1; - class Tab { - constructor() { - this.onItemSelectedChange_ = this.onItemSelectedChange_.bind(this); - this.empty = createValue(true); - this.selectedIndex = createValue(INDEX_NOT_SELECTED); - this.items_ = []; - } - add(item, opt_index) { - const index = opt_index !== null && opt_index !== void 0 ? opt_index : this.items_.length; - this.items_.splice(index, 0, item); - item.emitter.on('change', this.onItemSelectedChange_); - this.keepSelection_(); - } - remove(item) { - const index = this.items_.indexOf(item); - if (index < 0) { - return; - } - this.items_.splice(index, 1); - item.emitter.off('change', this.onItemSelectedChange_); - this.keepSelection_(); - } - keepSelection_() { - if (this.items_.length === 0) { - this.selectedIndex.rawValue = INDEX_NOT_SELECTED; - this.empty.rawValue = true; - return; - } - const firstSelIndex = this.items_.findIndex((s) => s.rawValue); - if (firstSelIndex < 0) { - this.items_.forEach((s, i) => { - s.rawValue = i === 0; - }); - this.selectedIndex.rawValue = 0; - } - else { - this.items_.forEach((s, i) => { - s.rawValue = i === firstSelIndex; - }); - this.selectedIndex.rawValue = firstSelIndex; - } - this.empty.rawValue = false; - } - onItemSelectedChange_(ev) { - if (ev.rawValue) { - const index = this.items_.findIndex((s) => s === ev.sender); - this.items_.forEach((s, i) => { - s.rawValue = i === index; - }); - this.selectedIndex.rawValue = index; - } - else { - this.keepSelection_(); - } - } - } - - const cn$k = ClassName('tab'); - class TabView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$k(), bladeContainerClassName()); - config.viewProps.bindClassModifiers(this.element); - bindValue(config.empty, valueToClassName(this.element, cn$k(undefined, 'nop'))); - const titleElem = doc.createElement('div'); - titleElem.classList.add(cn$k('t')); - this.element.appendChild(titleElem); - this.itemsElement = titleElem; - const indentElem = doc.createElement('div'); - indentElem.classList.add(cn$k('i')); - this.element.appendChild(indentElem); - const contentsElem = doc.createElement('div'); - contentsElem.classList.add(cn$k('c')); - this.element.appendChild(contentsElem); - this.contentsElement = contentsElem; - } - } - - class TabController extends ContainerBladeController { - constructor(doc, config) { - const tab = new Tab(); - const view = new TabView(doc, { - empty: tab.empty, - viewProps: config.viewProps, - }); - super({ - blade: config.blade, - rackController: new RackController({ - blade: config.blade, - element: view.contentsElement, - viewProps: config.viewProps, - }), - view: view, - }); - this.onRackAdd_ = this.onRackAdd_.bind(this); - this.onRackRemove_ = this.onRackRemove_.bind(this); - const rack = this.rackController.rack; - rack.emitter.on('add', this.onRackAdd_); - rack.emitter.on('remove', this.onRackRemove_); - this.tab = tab; - } - add(pc, opt_index) { - this.rackController.rack.add(pc, opt_index); - } - remove(index) { - this.rackController.rack.remove(this.rackController.rack.children[index]); - } - onRackAdd_(ev) { - if (!ev.root) { - return; - } - const pc = ev.bladeController; - insertElementAt(this.view.itemsElement, pc.itemController.view.element, ev.index); - pc.itemController.viewProps.set('parent', this.viewProps); - this.tab.add(pc.props.value('selected')); - } - onRackRemove_(ev) { - if (!ev.root) { - return; - } - const pc = ev.bladeController; - removeElement(pc.itemController.view.element); - pc.itemController.viewProps.set('parent', null); - this.tab.remove(pc.props.value('selected')); - } - } - - createPlugin({ - id: 'tab', - type: 'blade', - accept(params) { - const result = parseRecord(params, (p) => ({ - pages: p.required.array(p.required.object({ title: p.required.string })), - view: p.required.constant('tab'), - })); - if (!result || result.pages.length === 0) { - return null; - } - return { params: result }; - }, - controller(args) { - const c = new TabController(args.document, { - blade: args.blade, - viewProps: args.viewProps, - }); - args.params.pages.forEach((p) => { - const pc = new TabPageController(args.document, { - blade: createBlade(), - itemProps: ValueMap.fromObject({ - selected: false, - title: p.title, - }), - props: ValueMap.fromObject({ - selected: false, - }), - viewProps: ViewProps.create(), - }); - c.add(pc); - }); - return c; - }, - api(args) { - if (args.controller instanceof TabController) { - return new TabApi(args.controller, args.pool); - } - if (args.controller instanceof TabPageController) { - return new TabPageApi(args.controller, args.pool); - } - return null; - }, - }); - - class ListInputBindingApi extends BindingApi { - get options() { - return this.controller.valueController.props.get('options'); - } - set options(options) { - this.controller.valueController.props.set('options', options); - } - } - - class ManualTicker { - constructor() { - this.disabled = false; - this.emitter = new Emitter(); - } - dispose() { } - tick() { - if (this.disabled) { - return; - } - this.emitter.emit('tick', { - sender: this, - }); - } - } - - class IntervalTicker { - constructor(doc, interval) { - this.disabled_ = false; - this.timerId_ = null; - this.onTick_ = this.onTick_.bind(this); - this.doc_ = doc; - this.emitter = new Emitter(); - this.interval_ = interval; - this.setTimer_(); - } - get disabled() { - return this.disabled_; - } - set disabled(inactive) { - this.disabled_ = inactive; - if (this.disabled_) { - this.clearTimer_(); - } - else { - this.setTimer_(); - } - } - dispose() { - this.clearTimer_(); - } - clearTimer_() { - if (this.timerId_ === null) { - return; - } - const win = this.doc_.defaultView; - if (win) { - win.clearInterval(this.timerId_); - } - this.timerId_ = null; - } - setTimer_() { - this.clearTimer_(); - if (this.interval_ <= 0) { - return; - } - const win = this.doc_.defaultView; - if (win) { - this.timerId_ = win.setInterval(this.onTick_, this.interval_); - } - } - onTick_() { - if (this.disabled_) { - return; - } - this.emitter.emit('tick', { - sender: this, - }); - } - } - - class CompositeConstraint { - constructor(constraints) { - this.constraints = constraints; - } - constrain(value) { - return this.constraints.reduce((result, c) => { - return c.constrain(result); - }, value); - } - } - function findConstraint(c, constraintClass) { - if (c instanceof constraintClass) { - return c; - } - if (c instanceof CompositeConstraint) { - const result = c.constraints.reduce((tmpResult, sc) => { - if (tmpResult) { - return tmpResult; - } - return sc instanceof constraintClass ? sc : null; - }, null); - if (result) { - return result; - } - } - return null; - } - - class ListConstraint { - constructor(options) { - this.values = ValueMap.fromObject({ - options: options, - }); - } - constrain(value) { - const opts = this.values.get('options'); - if (opts.length === 0) { - return value; - } - const matched = opts.filter((item) => { - return item.value === value; - }).length > 0; - return matched ? value : opts[0].value; - } - } - - function parseListOptions(value) { - var _a; - const p = MicroParsers; - if (Array.isArray(value)) { - return (_a = parseRecord({ items: value }, (p) => ({ - items: p.required.array(p.required.object({ - text: p.required.string, - value: p.required.raw, - })), - }))) === null || _a === void 0 ? void 0 : _a.items; - } - if (typeof value === 'object') { - return p.required.raw(value) - .value; - } - return undefined; - } - function normalizeListOptions(options) { - if (Array.isArray(options)) { - return options; - } - const items = []; - Object.keys(options).forEach((text) => { - items.push({ text: text, value: options[text] }); - }); - return items; - } - function createListConstraint(options) { - return !isEmpty(options) - ? new ListConstraint(normalizeListOptions(forceCast(options))) - : null; - } - - const cn$j = ClassName('lst'); - class ListView { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.props_ = config.props; - this.element = doc.createElement('div'); - this.element.classList.add(cn$j()); - config.viewProps.bindClassModifiers(this.element); - const selectElem = doc.createElement('select'); - selectElem.classList.add(cn$j('s')); - config.viewProps.bindDisabled(selectElem); - this.element.appendChild(selectElem); - this.selectElement = selectElem; - const markElem = doc.createElement('div'); - markElem.classList.add(cn$j('m')); - markElem.appendChild(createSvgIconElement(doc, 'dropdown')); - this.element.appendChild(markElem); - config.value.emitter.on('change', this.onValueChange_); - this.value_ = config.value; - bindValueMap(this.props_, 'options', (opts) => { - removeChildElements(this.selectElement); - opts.forEach((item) => { - const optionElem = doc.createElement('option'); - optionElem.textContent = item.text; - this.selectElement.appendChild(optionElem); - }); - this.update_(); - }); - } - update_() { - const values = this.props_.get('options').map((o) => o.value); - this.selectElement.selectedIndex = values.indexOf(this.value_.rawValue); - } - onValueChange_() { - this.update_(); - } - } - - class ListController { - constructor(doc, config) { - this.onSelectChange_ = this.onSelectChange_.bind(this); - this.props = config.props; - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new ListView(doc, { - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - this.view.selectElement.addEventListener('change', this.onSelectChange_); - } - onSelectChange_(e) { - const selectElem = forceCast(e.currentTarget); - this.value.rawValue = - this.props.get('options')[selectElem.selectedIndex].value; - } - importProps(state) { - return importBladeState(state, null, (p) => ({ - options: p.required.custom(parseListOptions), - }), (result) => { - this.props.set('options', normalizeListOptions(result.options)); - return true; - }); - } - exportProps() { - return exportBladeState(null, { - options: this.props.get('options'), - }); - } - } - - const cn$i = ClassName('pop'); - class PopupView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$i()); - config.viewProps.bindClassModifiers(this.element); - bindValue(config.shows, valueToClassName(this.element, cn$i(undefined, 'v'))); - } - } - - class PopupController { - constructor(doc, config) { - this.shows = createValue(false); - this.viewProps = config.viewProps; - this.view = new PopupView(doc, { - shows: this.shows, - viewProps: this.viewProps, - }); - } - } - - const cn$h = ClassName('txt'); - class TextView { - constructor(doc, config) { - this.onChange_ = this.onChange_.bind(this); - this.element = doc.createElement('div'); - this.element.classList.add(cn$h()); - config.viewProps.bindClassModifiers(this.element); - this.props_ = config.props; - this.props_.emitter.on('change', this.onChange_); - const inputElem = doc.createElement('input'); - inputElem.classList.add(cn$h('i')); - inputElem.type = 'text'; - config.viewProps.bindDisabled(inputElem); - this.element.appendChild(inputElem); - this.inputElement = inputElem; - config.value.emitter.on('change', this.onChange_); - this.value_ = config.value; - this.refresh(); - } - refresh() { - const formatter = this.props_.get('formatter'); - this.inputElement.value = formatter(this.value_.rawValue); - } - onChange_() { - this.refresh(); - } - } - - class TextController { - constructor(doc, config) { - this.onInputChange_ = this.onInputChange_.bind(this); - this.parser_ = config.parser; - this.props = config.props; - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new TextView(doc, { - props: config.props, - value: this.value, - viewProps: this.viewProps, - }); - this.view.inputElement.addEventListener('change', this.onInputChange_); - } - onInputChange_(e) { - const inputElem = forceCast(e.currentTarget); - const value = inputElem.value; - const parsedValue = this.parser_(value); - if (!isEmpty(parsedValue)) { - this.value.rawValue = parsedValue; - } - this.view.refresh(); - } - } - - function boolToString(value) { - return String(value); - } - function boolFromUnknown(value) { - if (value === 'false') { - return false; - } - return !!value; - } - function BooleanFormatter(value) { - return boolToString(value); - } - - function composeParsers(parsers) { - return (text) => { - return parsers.reduce((result, parser) => { - if (result !== null) { - return result; - } - return parser(text); - }, null); - }; - } - - const innerFormatter = createNumberFormatter(0); - function formatPercentage(value) { - return innerFormatter(value) + '%'; - } - - function stringFromUnknown(value) { - return String(value); - } - function formatString(value) { - return value; - } - - function connectValues({ primary, secondary, forward, backward, }) { - let changing = false; - function preventFeedback(callback) { - if (changing) { - return; - } - changing = true; - callback(); - changing = false; - } - primary.emitter.on('change', (ev) => { - preventFeedback(() => { - secondary.setRawValue(forward(primary.rawValue, secondary.rawValue), ev.options); - }); - }); - secondary.emitter.on('change', (ev) => { - preventFeedback(() => { - primary.setRawValue(backward(primary.rawValue, secondary.rawValue), ev.options); - }); - preventFeedback(() => { - secondary.setRawValue(forward(primary.rawValue, secondary.rawValue), ev.options); - }); - }); - preventFeedback(() => { - secondary.setRawValue(forward(primary.rawValue, secondary.rawValue), { - forceEmit: false, - last: true, - }); - }); - } - - function getStepForKey(keyScale, keys) { - const step = keyScale * (keys.altKey ? 0.1 : 1) * (keys.shiftKey ? 10 : 1); - if (keys.upKey) { - return +step; - } - else if (keys.downKey) { - return -step; - } - return 0; - } - function getVerticalStepKeys(ev) { - return { - altKey: ev.altKey, - downKey: ev.key === 'ArrowDown', - shiftKey: ev.shiftKey, - upKey: ev.key === 'ArrowUp', - }; - } - function getHorizontalStepKeys(ev) { - return { - altKey: ev.altKey, - downKey: ev.key === 'ArrowLeft', - shiftKey: ev.shiftKey, - upKey: ev.key === 'ArrowRight', - }; - } - function isVerticalArrowKey(key) { - return key === 'ArrowUp' || key === 'ArrowDown'; - } - function isArrowKey(key) { - return isVerticalArrowKey(key) || key === 'ArrowLeft' || key === 'ArrowRight'; - } - - function computeOffset$1(ev, elem) { - var _a, _b; - const win = elem.ownerDocument.defaultView; - const rect = elem.getBoundingClientRect(); - return { - x: ev.pageX - (((_a = (win && win.scrollX)) !== null && _a !== void 0 ? _a : 0) + rect.left), - y: ev.pageY - (((_b = (win && win.scrollY)) !== null && _b !== void 0 ? _b : 0) + rect.top), - }; - } - class PointerHandler { - constructor(element) { - this.lastTouch_ = null; - this.onDocumentMouseMove_ = this.onDocumentMouseMove_.bind(this); - this.onDocumentMouseUp_ = this.onDocumentMouseUp_.bind(this); - this.onMouseDown_ = this.onMouseDown_.bind(this); - this.onTouchEnd_ = this.onTouchEnd_.bind(this); - this.onTouchMove_ = this.onTouchMove_.bind(this); - this.onTouchStart_ = this.onTouchStart_.bind(this); - this.elem_ = element; - this.emitter = new Emitter(); - element.addEventListener('touchstart', this.onTouchStart_, { - passive: false, - }); - element.addEventListener('touchmove', this.onTouchMove_, { - passive: true, - }); - element.addEventListener('touchend', this.onTouchEnd_); - element.addEventListener('mousedown', this.onMouseDown_); - } - computePosition_(offset) { - const rect = this.elem_.getBoundingClientRect(); - return { - bounds: { - width: rect.width, - height: rect.height, - }, - point: offset - ? { - x: offset.x, - y: offset.y, - } - : null, - }; - } - onMouseDown_(ev) { - var _a; - ev.preventDefault(); - (_a = ev.currentTarget) === null || _a === void 0 ? void 0 : _a.focus(); - const doc = this.elem_.ownerDocument; - doc.addEventListener('mousemove', this.onDocumentMouseMove_); - doc.addEventListener('mouseup', this.onDocumentMouseUp_); - this.emitter.emit('down', { - altKey: ev.altKey, - data: this.computePosition_(computeOffset$1(ev, this.elem_)), - sender: this, - shiftKey: ev.shiftKey, - }); - } - onDocumentMouseMove_(ev) { - this.emitter.emit('move', { - altKey: ev.altKey, - data: this.computePosition_(computeOffset$1(ev, this.elem_)), - sender: this, - shiftKey: ev.shiftKey, - }); - } - onDocumentMouseUp_(ev) { - const doc = this.elem_.ownerDocument; - doc.removeEventListener('mousemove', this.onDocumentMouseMove_); - doc.removeEventListener('mouseup', this.onDocumentMouseUp_); - this.emitter.emit('up', { - altKey: ev.altKey, - data: this.computePosition_(computeOffset$1(ev, this.elem_)), - sender: this, - shiftKey: ev.shiftKey, - }); - } - onTouchStart_(ev) { - ev.preventDefault(); - const touch = ev.targetTouches.item(0); - const rect = this.elem_.getBoundingClientRect(); - this.emitter.emit('down', { - altKey: ev.altKey, - data: this.computePosition_(touch - ? { - x: touch.clientX - rect.left, - y: touch.clientY - rect.top, - } - : undefined), - sender: this, - shiftKey: ev.shiftKey, - }); - this.lastTouch_ = touch; - } - onTouchMove_(ev) { - const touch = ev.targetTouches.item(0); - const rect = this.elem_.getBoundingClientRect(); - this.emitter.emit('move', { - altKey: ev.altKey, - data: this.computePosition_(touch - ? { - x: touch.clientX - rect.left, - y: touch.clientY - rect.top, - } - : undefined), - sender: this, - shiftKey: ev.shiftKey, - }); - this.lastTouch_ = touch; - } - onTouchEnd_(ev) { - var _a; - const touch = (_a = ev.targetTouches.item(0)) !== null && _a !== void 0 ? _a : this.lastTouch_; - const rect = this.elem_.getBoundingClientRect(); - this.emitter.emit('up', { - altKey: ev.altKey, - data: this.computePosition_(touch - ? { - x: touch.clientX - rect.left, - y: touch.clientY - rect.top, - } - : undefined), - sender: this, - shiftKey: ev.shiftKey, - }); - } - } - - const cn$g = ClassName('txt'); - class NumberTextView { - constructor(doc, config) { - this.onChange_ = this.onChange_.bind(this); - this.props_ = config.props; - this.props_.emitter.on('change', this.onChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$g(), cn$g(undefined, 'num')); - if (config.arrayPosition) { - this.element.classList.add(cn$g(undefined, config.arrayPosition)); - } - config.viewProps.bindClassModifiers(this.element); - const inputElem = doc.createElement('input'); - inputElem.classList.add(cn$g('i')); - inputElem.type = 'text'; - config.viewProps.bindDisabled(inputElem); - this.element.appendChild(inputElem); - this.inputElement = inputElem; - this.onDraggingChange_ = this.onDraggingChange_.bind(this); - this.dragging_ = config.dragging; - this.dragging_.emitter.on('change', this.onDraggingChange_); - this.element.classList.add(cn$g()); - this.inputElement.classList.add(cn$g('i')); - const knobElem = doc.createElement('div'); - knobElem.classList.add(cn$g('k')); - this.element.appendChild(knobElem); - this.knobElement = knobElem; - const guideElem = doc.createElementNS(SVG_NS, 'svg'); - guideElem.classList.add(cn$g('g')); - this.knobElement.appendChild(guideElem); - const bodyElem = doc.createElementNS(SVG_NS, 'path'); - bodyElem.classList.add(cn$g('gb')); - guideElem.appendChild(bodyElem); - this.guideBodyElem_ = bodyElem; - const headElem = doc.createElementNS(SVG_NS, 'path'); - headElem.classList.add(cn$g('gh')); - guideElem.appendChild(headElem); - this.guideHeadElem_ = headElem; - const tooltipElem = doc.createElement('div'); - tooltipElem.classList.add(ClassName('tt')()); - this.knobElement.appendChild(tooltipElem); - this.tooltipElem_ = tooltipElem; - config.value.emitter.on('change', this.onChange_); - this.value = config.value; - this.refresh(); - } - onDraggingChange_(ev) { - if (ev.rawValue === null) { - this.element.classList.remove(cn$g(undefined, 'drg')); - return; - } - this.element.classList.add(cn$g(undefined, 'drg')); - const x = ev.rawValue / this.props_.get('pointerScale'); - const aox = x + (x > 0 ? -1 : x < 0 ? +1 : 0); - const adx = constrainRange(-aox, -4, +4); - this.guideHeadElem_.setAttributeNS(null, 'd', [`M ${aox + adx},0 L${aox},4 L${aox + adx},8`, `M ${x},-1 L${x},9`].join(' ')); - this.guideBodyElem_.setAttributeNS(null, 'd', `M 0,4 L${x},4`); - const formatter = this.props_.get('formatter'); - this.tooltipElem_.textContent = formatter(this.value.rawValue); - this.tooltipElem_.style.left = `${x}px`; - } - refresh() { - const formatter = this.props_.get('formatter'); - this.inputElement.value = formatter(this.value.rawValue); - } - onChange_() { - this.refresh(); - } - } - - class NumberTextController { - constructor(doc, config) { - var _a; - this.originRawValue_ = 0; - this.onInputChange_ = this.onInputChange_.bind(this); - this.onInputKeyDown_ = this.onInputKeyDown_.bind(this); - this.onInputKeyUp_ = this.onInputKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.parser_ = config.parser; - this.props = config.props; - this.sliderProps_ = (_a = config.sliderProps) !== null && _a !== void 0 ? _a : null; - this.value = config.value; - this.viewProps = config.viewProps; - this.dragging_ = createValue(null); - this.view = new NumberTextView(doc, { - arrayPosition: config.arrayPosition, - dragging: this.dragging_, - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - this.view.inputElement.addEventListener('change', this.onInputChange_); - this.view.inputElement.addEventListener('keydown', this.onInputKeyDown_); - this.view.inputElement.addEventListener('keyup', this.onInputKeyUp_); - const ph = new PointerHandler(this.view.knobElement); - ph.emitter.on('down', this.onPointerDown_); - ph.emitter.on('move', this.onPointerMove_); - ph.emitter.on('up', this.onPointerUp_); - } - constrainValue_(value) { - var _a, _b; - const min = (_a = this.sliderProps_) === null || _a === void 0 ? void 0 : _a.get('min'); - const max = (_b = this.sliderProps_) === null || _b === void 0 ? void 0 : _b.get('max'); - let v = value; - if (min !== undefined) { - v = Math.max(v, min); - } - if (max !== undefined) { - v = Math.min(v, max); - } - return v; - } - onInputChange_(e) { - const inputElem = forceCast(e.currentTarget); - const value = inputElem.value; - const parsedValue = this.parser_(value); - if (!isEmpty(parsedValue)) { - this.value.rawValue = this.constrainValue_(parsedValue); - } - this.view.refresh(); - } - onInputKeyDown_(ev) { - const step = getStepForKey(this.props.get('keyScale'), getVerticalStepKeys(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.constrainValue_(this.value.rawValue + step), { - forceEmit: false, - last: false, - }); - } - onInputKeyUp_(ev) { - const step = getStepForKey(this.props.get('keyScale'), getVerticalStepKeys(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - onPointerDown_() { - this.originRawValue_ = this.value.rawValue; - this.dragging_.rawValue = 0; - } - computeDraggingValue_(data) { - if (!data.point) { - return null; - } - const dx = data.point.x - data.bounds.width / 2; - return this.constrainValue_(this.originRawValue_ + dx * this.props.get('pointerScale')); - } - onPointerMove_(ev) { - const v = this.computeDraggingValue_(ev.data); - if (v === null) { - return; - } - this.value.setRawValue(v, { - forceEmit: false, - last: false, - }); - this.dragging_.rawValue = this.value.rawValue - this.originRawValue_; - } - onPointerUp_(ev) { - const v = this.computeDraggingValue_(ev.data); - if (v === null) { - return; - } - this.value.setRawValue(v, { - forceEmit: true, - last: true, - }); - this.dragging_.rawValue = null; - } - } - - const cn$f = ClassName('sld'); - class SliderView { - constructor(doc, config) { - this.onChange_ = this.onChange_.bind(this); - this.props_ = config.props; - this.props_.emitter.on('change', this.onChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$f()); - config.viewProps.bindClassModifiers(this.element); - const trackElem = doc.createElement('div'); - trackElem.classList.add(cn$f('t')); - config.viewProps.bindTabIndex(trackElem); - this.element.appendChild(trackElem); - this.trackElement = trackElem; - const knobElem = doc.createElement('div'); - knobElem.classList.add(cn$f('k')); - this.trackElement.appendChild(knobElem); - this.knobElement = knobElem; - config.value.emitter.on('change', this.onChange_); - this.value = config.value; - this.update_(); - } - update_() { - const p = constrainRange(mapRange(this.value.rawValue, this.props_.get('min'), this.props_.get('max'), 0, 100), 0, 100); - this.knobElement.style.width = `${p}%`; - } - onChange_() { - this.update_(); - } - } - - class SliderController { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDownOrMove_ = this.onPointerDownOrMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.props = config.props; - this.view = new SliderView(doc, { - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler(this.view.trackElement); - this.ptHandler_.emitter.on('down', this.onPointerDownOrMove_); - this.ptHandler_.emitter.on('move', this.onPointerDownOrMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.trackElement.addEventListener('keydown', this.onKeyDown_); - this.view.trackElement.addEventListener('keyup', this.onKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - this.value.setRawValue(mapRange(constrainRange(d.point.x, 0, d.bounds.width), 0, d.bounds.width, this.props.get('min'), this.props.get('max')), opts); - } - onPointerDownOrMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - const step = getStepForKey(this.props.get('keyScale'), getHorizontalStepKeys(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue + step, { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - const step = getStepForKey(this.props.get('keyScale'), getHorizontalStepKeys(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - const cn$e = ClassName('sldtxt'); - class SliderTextView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$e()); - const sliderElem = doc.createElement('div'); - sliderElem.classList.add(cn$e('s')); - this.sliderView_ = config.sliderView; - sliderElem.appendChild(this.sliderView_.element); - this.element.appendChild(sliderElem); - const textElem = doc.createElement('div'); - textElem.classList.add(cn$e('t')); - this.textView_ = config.textView; - textElem.appendChild(this.textView_.element); - this.element.appendChild(textElem); - } - } - - class SliderTextController { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.sliderC_ = new SliderController(doc, { - props: config.sliderProps, - value: config.value, - viewProps: this.viewProps, - }); - this.textC_ = new NumberTextController(doc, { - parser: config.parser, - props: config.textProps, - sliderProps: config.sliderProps, - value: config.value, - viewProps: config.viewProps, - }); - this.view = new SliderTextView(doc, { - sliderView: this.sliderC_.view, - textView: this.textC_.view, - }); - } - get sliderController() { - return this.sliderC_; - } - get textController() { - return this.textC_; - } - importProps(state) { - return importBladeState(state, null, (p) => ({ - max: p.required.number, - min: p.required.number, - }), (result) => { - const sliderProps = this.sliderC_.props; - sliderProps.set('max', result.max); - sliderProps.set('min', result.min); - return true; - }); - } - exportProps() { - const sliderProps = this.sliderC_.props; - return exportBladeState(null, { - max: sliderProps.get('max'), - min: sliderProps.get('min'), - }); - } - } - function createSliderTextProps(config) { - return { - sliderProps: new ValueMap({ - keyScale: config.keyScale, - max: config.max, - min: config.min, - }), - textProps: new ValueMap({ - formatter: createValue(config.formatter), - keyScale: config.keyScale, - pointerScale: createValue(config.pointerScale), - }), - }; - } - - const CSS_VAR_MAP = { - containerUnitSize: 'cnt-usz', - }; - function getCssVar(key) { - return `--${CSS_VAR_MAP[key]}`; - } - - class PlainView { - constructor(doc, config) { - const cn = ClassName(config.viewName); - this.element = doc.createElement('div'); - this.element.classList.add(cn()); - config.viewProps.bindClassModifiers(this.element); - } - } - - function createPointDimensionParser(p) { - return createNumberTextInputParamsParser(p); - } - function parsePointDimensionParams(value) { - if (!isRecord(value)) { - return undefined; - } - return parseRecord(value, createPointDimensionParser); - } - function createDimensionConstraint(params, initialValue) { - if (!params) { - return undefined; - } - const constraints = []; - const cs = createStepConstraint(params, initialValue); - if (cs) { - constraints.push(cs); - } - const rs = createRangeConstraint(params); - if (rs) { - constraints.push(rs); - } - return new CompositeConstraint(constraints); - } - - function parsePickerLayout(value) { - if (value === 'inline' || value === 'popup') { - return value; - } - return undefined; - } - - function writePrimitive(target, value) { - target.write(value); - } - - const cn$d = ClassName('ckb'); - class CheckboxView { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.element = doc.createElement('div'); - this.element.classList.add(cn$d()); - config.viewProps.bindClassModifiers(this.element); - const labelElem = doc.createElement('label'); - labelElem.classList.add(cn$d('l')); - this.element.appendChild(labelElem); - const inputElem = doc.createElement('input'); - inputElem.classList.add(cn$d('i')); - inputElem.type = 'checkbox'; - labelElem.appendChild(inputElem); - this.inputElement = inputElem; - config.viewProps.bindDisabled(this.inputElement); - const wrapperElem = doc.createElement('div'); - wrapperElem.classList.add(cn$d('w')); - labelElem.appendChild(wrapperElem); - const markElem = createSvgIconElement(doc, 'check'); - wrapperElem.appendChild(markElem); - config.value.emitter.on('change', this.onValueChange_); - this.value = config.value; - this.update_(); - } - update_() { - this.inputElement.checked = this.value.rawValue; - } - onValueChange_() { - this.update_(); - } - } - - class CheckboxController { - constructor(doc, config) { - this.onInputChange_ = this.onInputChange_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new CheckboxView(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.view.inputElement.addEventListener('change', this.onInputChange_); - } - onInputChange_(e) { - const inputElem = forceCast(e.currentTarget); - this.value.rawValue = inputElem.checked; - } - } - - function createConstraint$8(params) { - const constraints = []; - const lc = createListConstraint(params.options); - if (lc) { - constraints.push(lc); - } - return new CompositeConstraint(constraints); - } - createPlugin({ - id: 'input-bool', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'boolean') { - return null; - } - const result = parseRecord(params, (p) => ({ - options: p.optional.custom(parseListOptions), - readonly: p.optional.constant(false), - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => boolFromUnknown, - constraint: (args) => createConstraint$8(args.params), - writer: (_args) => writePrimitive, - }, - controller: (args) => { - const doc = args.document; - const value = args.value; - const c = args.constraint; - const lc = c && findConstraint(c, ListConstraint); - if (lc) { - return new ListController(doc, { - props: new ValueMap({ - options: lc.values.value('options'), - }), - value: value, - viewProps: args.viewProps, - }); - } - return new CheckboxController(doc, { - value: value, - viewProps: args.viewProps, - }); - }, - api(args) { - if (typeof args.controller.value.rawValue !== 'boolean') { - return null; - } - if (args.controller.valueController instanceof ListController) { - return new ListInputBindingApi(args.controller); - } - return null; - }, - }); - - const cn$c = ClassName('col'); - class ColorView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$c()); - config.foldable.bindExpandedClass(this.element, cn$c(undefined, 'expanded')); - bindValueMap(config.foldable, 'completed', valueToClassName(this.element, cn$c(undefined, 'cpl'))); - const headElem = doc.createElement('div'); - headElem.classList.add(cn$c('h')); - this.element.appendChild(headElem); - const swatchElem = doc.createElement('div'); - swatchElem.classList.add(cn$c('s')); - headElem.appendChild(swatchElem); - this.swatchElement = swatchElem; - const textElem = doc.createElement('div'); - textElem.classList.add(cn$c('t')); - headElem.appendChild(textElem); - this.textElement = textElem; - if (config.pickerLayout === 'inline') { - const pickerElem = doc.createElement('div'); - pickerElem.classList.add(cn$c('p')); - this.element.appendChild(pickerElem); - this.pickerElement = pickerElem; - } - else { - this.pickerElement = null; - } - } - } - - function rgbToHslInt(r, g, b) { - const rp = constrainRange(r / 255, 0, 1); - const gp = constrainRange(g / 255, 0, 1); - const bp = constrainRange(b / 255, 0, 1); - const cmax = Math.max(rp, gp, bp); - const cmin = Math.min(rp, gp, bp); - const c = cmax - cmin; - let h = 0; - let s = 0; - const l = (cmin + cmax) / 2; - if (c !== 0) { - s = c / (1 - Math.abs(cmax + cmin - 1)); - if (rp === cmax) { - h = (gp - bp) / c; - } - else if (gp === cmax) { - h = 2 + (bp - rp) / c; - } - else { - h = 4 + (rp - gp) / c; - } - h = h / 6 + (h < 0 ? 1 : 0); - } - return [h * 360, s * 100, l * 100]; - } - function hslToRgbInt(h, s, l) { - const hp = ((h % 360) + 360) % 360; - const sp = constrainRange(s / 100, 0, 1); - const lp = constrainRange(l / 100, 0, 1); - const c = (1 - Math.abs(2 * lp - 1)) * sp; - const x = c * (1 - Math.abs(((hp / 60) % 2) - 1)); - const m = lp - c / 2; - let rp, gp, bp; - if (hp >= 0 && hp < 60) { - [rp, gp, bp] = [c, x, 0]; - } - else if (hp >= 60 && hp < 120) { - [rp, gp, bp] = [x, c, 0]; - } - else if (hp >= 120 && hp < 180) { - [rp, gp, bp] = [0, c, x]; - } - else if (hp >= 180 && hp < 240) { - [rp, gp, bp] = [0, x, c]; - } - else if (hp >= 240 && hp < 300) { - [rp, gp, bp] = [x, 0, c]; - } - else { - [rp, gp, bp] = [c, 0, x]; - } - return [(rp + m) * 255, (gp + m) * 255, (bp + m) * 255]; - } - function rgbToHsvInt(r, g, b) { - const rp = constrainRange(r / 255, 0, 1); - const gp = constrainRange(g / 255, 0, 1); - const bp = constrainRange(b / 255, 0, 1); - const cmax = Math.max(rp, gp, bp); - const cmin = Math.min(rp, gp, bp); - const d = cmax - cmin; - let h; - if (d === 0) { - h = 0; - } - else if (cmax === rp) { - h = 60 * (((((gp - bp) / d) % 6) + 6) % 6); - } - else if (cmax === gp) { - h = 60 * ((bp - rp) / d + 2); - } - else { - h = 60 * ((rp - gp) / d + 4); - } - const s = cmax === 0 ? 0 : d / cmax; - const v = cmax; - return [h, s * 100, v * 100]; - } - function hsvToRgbInt(h, s, v) { - const hp = loopRange(h, 360); - const sp = constrainRange(s / 100, 0, 1); - const vp = constrainRange(v / 100, 0, 1); - const c = vp * sp; - const x = c * (1 - Math.abs(((hp / 60) % 2) - 1)); - const m = vp - c; - let rp, gp, bp; - if (hp >= 0 && hp < 60) { - [rp, gp, bp] = [c, x, 0]; - } - else if (hp >= 60 && hp < 120) { - [rp, gp, bp] = [x, c, 0]; - } - else if (hp >= 120 && hp < 180) { - [rp, gp, bp] = [0, c, x]; - } - else if (hp >= 180 && hp < 240) { - [rp, gp, bp] = [0, x, c]; - } - else if (hp >= 240 && hp < 300) { - [rp, gp, bp] = [x, 0, c]; - } - else { - [rp, gp, bp] = [c, 0, x]; - } - return [(rp + m) * 255, (gp + m) * 255, (bp + m) * 255]; - } - function hslToHsvInt(h, s, l) { - const sd = l + (s * (100 - Math.abs(2 * l - 100))) / (2 * 100); - return [ - h, - sd !== 0 ? (s * (100 - Math.abs(2 * l - 100))) / sd : 0, - l + (s * (100 - Math.abs(2 * l - 100))) / (2 * 100), - ]; - } - function hsvToHslInt(h, s, v) { - const sd = 100 - Math.abs((v * (200 - s)) / 100 - 100); - return [h, sd !== 0 ? (s * v) / sd : 0, (v * (200 - s)) / (2 * 100)]; - } - function removeAlphaComponent(comps) { - return [comps[0], comps[1], comps[2]]; - } - function appendAlphaComponent(comps, alpha) { - return [comps[0], comps[1], comps[2], alpha]; - } - const MODE_CONVERTER_MAP = { - hsl: { - hsl: (h, s, l) => [h, s, l], - hsv: hslToHsvInt, - rgb: hslToRgbInt, - }, - hsv: { - hsl: hsvToHslInt, - hsv: (h, s, v) => [h, s, v], - rgb: hsvToRgbInt, - }, - rgb: { - hsl: rgbToHslInt, - hsv: rgbToHsvInt, - rgb: (r, g, b) => [r, g, b], - }, - }; - function getColorMaxComponents(mode, type) { - return [ - type === 'float' ? 1 : mode === 'rgb' ? 255 : 360, - type === 'float' ? 1 : mode === 'rgb' ? 255 : 100, - type === 'float' ? 1 : mode === 'rgb' ? 255 : 100, - ]; - } - function loopHueRange(hue, max) { - return hue === max ? max : loopRange(hue, max); - } - function constrainColorComponents(components, mode, type) { - var _a; - const ms = getColorMaxComponents(mode, type); - return [ - mode === 'rgb' - ? constrainRange(components[0], 0, ms[0]) - : loopHueRange(components[0], ms[0]), - constrainRange(components[1], 0, ms[1]), - constrainRange(components[2], 0, ms[2]), - constrainRange((_a = components[3]) !== null && _a !== void 0 ? _a : 1, 0, 1), - ]; - } - function convertColorType(comps, mode, from, to) { - const fms = getColorMaxComponents(mode, from); - const tms = getColorMaxComponents(mode, to); - return comps.map((c, index) => (c / fms[index]) * tms[index]); - } - function convertColor(components, from, to) { - const intComps = convertColorType(components, from.mode, from.type, 'int'); - const result = MODE_CONVERTER_MAP[from.mode][to.mode](...intComps); - return convertColorType(result, to.mode, 'int', to.type); - } - - class IntColor { - static black() { - return new IntColor([0, 0, 0], 'rgb'); - } - constructor(comps, mode) { - this.type = 'int'; - this.mode = mode; - this.comps_ = constrainColorComponents(comps, mode, this.type); - } - getComponents(opt_mode) { - return appendAlphaComponent(convertColor(removeAlphaComponent(this.comps_), { mode: this.mode, type: this.type }, { mode: opt_mode !== null && opt_mode !== void 0 ? opt_mode : this.mode, type: this.type }), this.comps_[3]); - } - toRgbaObject() { - const rgbComps = this.getComponents('rgb'); - return { - r: rgbComps[0], - g: rgbComps[1], - b: rgbComps[2], - a: rgbComps[3], - }; - } - } - - const cn$b = ClassName('colp'); - class ColorPickerView { - constructor(doc, config) { - this.alphaViews_ = null; - this.element = doc.createElement('div'); - this.element.classList.add(cn$b()); - config.viewProps.bindClassModifiers(this.element); - const hsvElem = doc.createElement('div'); - hsvElem.classList.add(cn$b('hsv')); - const svElem = doc.createElement('div'); - svElem.classList.add(cn$b('sv')); - this.svPaletteView_ = config.svPaletteView; - svElem.appendChild(this.svPaletteView_.element); - hsvElem.appendChild(svElem); - const hElem = doc.createElement('div'); - hElem.classList.add(cn$b('h')); - this.hPaletteView_ = config.hPaletteView; - hElem.appendChild(this.hPaletteView_.element); - hsvElem.appendChild(hElem); - this.element.appendChild(hsvElem); - const rgbElem = doc.createElement('div'); - rgbElem.classList.add(cn$b('rgb')); - this.textsView_ = config.textsView; - rgbElem.appendChild(this.textsView_.element); - this.element.appendChild(rgbElem); - if (config.alphaViews) { - this.alphaViews_ = { - palette: config.alphaViews.palette, - text: config.alphaViews.text, - }; - const aElem = doc.createElement('div'); - aElem.classList.add(cn$b('a')); - const apElem = doc.createElement('div'); - apElem.classList.add(cn$b('ap')); - apElem.appendChild(this.alphaViews_.palette.element); - aElem.appendChild(apElem); - const atElem = doc.createElement('div'); - atElem.classList.add(cn$b('at')); - atElem.appendChild(this.alphaViews_.text.element); - aElem.appendChild(atElem); - this.element.appendChild(aElem); - } - } - get allFocusableElements() { - const elems = [ - this.svPaletteView_.element, - this.hPaletteView_.element, - this.textsView_.modeSelectElement, - ...this.textsView_.inputViews.map((v) => v.inputElement), - ]; - if (this.alphaViews_) { - elems.push(this.alphaViews_.palette.element, this.alphaViews_.text.inputElement); - } - return elems; - } - } - - function parseColorType(value) { - return value === 'int' ? 'int' : value === 'float' ? 'float' : undefined; - } - function parseColorInputParams(params) { - return parseRecord(params, (p) => ({ - color: p.optional.object({ - alpha: p.optional.boolean, - type: p.optional.custom(parseColorType), - }), - expanded: p.optional.boolean, - picker: p.optional.custom(parsePickerLayout), - readonly: p.optional.constant(false), - })); - } - function getKeyScaleForColor(forAlpha) { - return forAlpha ? 0.1 : 1; - } - function extractColorType(params) { - var _a; - return (_a = params.color) === null || _a === void 0 ? void 0 : _a.type; - } - - class FloatColor { - constructor(comps, mode) { - this.type = 'float'; - this.mode = mode; - this.comps_ = constrainColorComponents(comps, mode, this.type); - } - getComponents(opt_mode) { - return appendAlphaComponent(convertColor(removeAlphaComponent(this.comps_), { mode: this.mode, type: this.type }, { mode: opt_mode !== null && opt_mode !== void 0 ? opt_mode : this.mode, type: this.type }), this.comps_[3]); - } - toRgbaObject() { - const rgbComps = this.getComponents('rgb'); - return { - r: rgbComps[0], - g: rgbComps[1], - b: rgbComps[2], - a: rgbComps[3], - }; - } - } - - const TYPE_TO_CONSTRUCTOR_MAP = { - int: (comps, mode) => new IntColor(comps, mode), - float: (comps, mode) => new FloatColor(comps, mode), - }; - function createColor(comps, mode, type) { - return TYPE_TO_CONSTRUCTOR_MAP[type](comps, mode); - } - function isFloatColor(c) { - return c.type === 'float'; - } - function isIntColor(c) { - return c.type === 'int'; - } - function convertFloatToInt(cf) { - const comps = cf.getComponents(); - const ms = getColorMaxComponents(cf.mode, 'int'); - return new IntColor([ - Math.round(mapRange(comps[0], 0, 1, 0, ms[0])), - Math.round(mapRange(comps[1], 0, 1, 0, ms[1])), - Math.round(mapRange(comps[2], 0, 1, 0, ms[2])), - comps[3], - ], cf.mode); - } - function convertIntToFloat(ci) { - const comps = ci.getComponents(); - const ms = getColorMaxComponents(ci.mode, 'int'); - return new FloatColor([ - mapRange(comps[0], 0, ms[0], 0, 1), - mapRange(comps[1], 0, ms[1], 0, 1), - mapRange(comps[2], 0, ms[2], 0, 1), - comps[3], - ], ci.mode); - } - function mapColorType(c, type) { - if (c.type === type) { - return c; - } - if (isIntColor(c) && type === 'float') { - return convertIntToFloat(c); - } - if (isFloatColor(c) && type === 'int') { - return convertFloatToInt(c); - } - throw TpError.shouldNeverHappen(); - } - - function equalsStringColorFormat(f1, f2) { - return (f1.alpha === f2.alpha && - f1.mode === f2.mode && - f1.notation === f2.notation && - f1.type === f2.type); - } - function parseCssNumberOrPercentage(text, max) { - const m = text.match(/^(.+)%$/); - if (!m) { - return Math.min(parseFloat(text), max); - } - return Math.min(parseFloat(m[1]) * 0.01 * max, max); - } - const ANGLE_TO_DEG_MAP = { - deg: (angle) => angle, - grad: (angle) => (angle * 360) / 400, - rad: (angle) => (angle * 360) / (2 * Math.PI), - turn: (angle) => angle * 360, - }; - function parseCssNumberOrAngle(text) { - const m = text.match(/^([0-9.]+?)(deg|grad|rad|turn)$/); - if (!m) { - return parseFloat(text); - } - const angle = parseFloat(m[1]); - const unit = m[2]; - return ANGLE_TO_DEG_MAP[unit](angle); - } - function parseFunctionalRgbColorComponents(text) { - const m = text.match(/^rgb\(\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/); - if (!m) { - return null; - } - const comps = [ - parseCssNumberOrPercentage(m[1], 255), - parseCssNumberOrPercentage(m[2], 255), - parseCssNumberOrPercentage(m[3], 255), - ]; - if (isNaN(comps[0]) || isNaN(comps[1]) || isNaN(comps[2])) { - return null; - } - return comps; - } - function parseFunctionalRgbColor(text) { - const comps = parseFunctionalRgbColorComponents(text); - return comps ? new IntColor(comps, 'rgb') : null; - } - function parseFunctionalRgbaColorComponents(text) { - const m = text.match(/^rgba\(\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/); - if (!m) { - return null; - } - const comps = [ - parseCssNumberOrPercentage(m[1], 255), - parseCssNumberOrPercentage(m[2], 255), - parseCssNumberOrPercentage(m[3], 255), - parseCssNumberOrPercentage(m[4], 1), - ]; - if (isNaN(comps[0]) || - isNaN(comps[1]) || - isNaN(comps[2]) || - isNaN(comps[3])) { - return null; - } - return comps; - } - function parseFunctionalRgbaColor(text) { - const comps = parseFunctionalRgbaColorComponents(text); - return comps ? new IntColor(comps, 'rgb') : null; - } - function parseFunctionalHslColorComponents(text) { - const m = text.match(/^hsl\(\s*([0-9A-Fa-f.]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/); - if (!m) { - return null; - } - const comps = [ - parseCssNumberOrAngle(m[1]), - parseCssNumberOrPercentage(m[2], 100), - parseCssNumberOrPercentage(m[3], 100), - ]; - if (isNaN(comps[0]) || isNaN(comps[1]) || isNaN(comps[2])) { - return null; - } - return comps; - } - function parseFunctionalHslColor(text) { - const comps = parseFunctionalHslColorComponents(text); - return comps ? new IntColor(comps, 'hsl') : null; - } - function parseHslaColorComponents(text) { - const m = text.match(/^hsla\(\s*([0-9A-Fa-f.]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/); - if (!m) { - return null; - } - const comps = [ - parseCssNumberOrAngle(m[1]), - parseCssNumberOrPercentage(m[2], 100), - parseCssNumberOrPercentage(m[3], 100), - parseCssNumberOrPercentage(m[4], 1), - ]; - if (isNaN(comps[0]) || - isNaN(comps[1]) || - isNaN(comps[2]) || - isNaN(comps[3])) { - return null; - } - return comps; - } - function parseFunctionalHslaColor(text) { - const comps = parseHslaColorComponents(text); - return comps ? new IntColor(comps, 'hsl') : null; - } - function parseHexRgbColorComponents(text) { - const mRgb = text.match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/); - if (mRgb) { - return [ - parseInt(mRgb[1] + mRgb[1], 16), - parseInt(mRgb[2] + mRgb[2], 16), - parseInt(mRgb[3] + mRgb[3], 16), - ]; - } - const mRrggbb = text.match(/^(?:#|0x)([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/); - if (mRrggbb) { - return [ - parseInt(mRrggbb[1], 16), - parseInt(mRrggbb[2], 16), - parseInt(mRrggbb[3], 16), - ]; - } - return null; - } - function parseHexRgbColor(text) { - const comps = parseHexRgbColorComponents(text); - return comps ? new IntColor(comps, 'rgb') : null; - } - function parseHexRgbaColorComponents(text) { - const mRgb = text.match(/^#?([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/); - if (mRgb) { - return [ - parseInt(mRgb[1] + mRgb[1], 16), - parseInt(mRgb[2] + mRgb[2], 16), - parseInt(mRgb[3] + mRgb[3], 16), - mapRange(parseInt(mRgb[4] + mRgb[4], 16), 0, 255, 0, 1), - ]; - } - const mRrggbb = text.match(/^(?:#|0x)?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/); - if (mRrggbb) { - return [ - parseInt(mRrggbb[1], 16), - parseInt(mRrggbb[2], 16), - parseInt(mRrggbb[3], 16), - mapRange(parseInt(mRrggbb[4], 16), 0, 255, 0, 1), - ]; - } - return null; - } - function parseHexRgbaColor(text) { - const comps = parseHexRgbaColorComponents(text); - return comps ? new IntColor(comps, 'rgb') : null; - } - function parseObjectRgbColorComponents(text) { - const m = text.match(/^\{\s*r\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*g\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*b\s*:\s*([0-9A-Fa-f.]+%?)\s*\}$/); - if (!m) { - return null; - } - const comps = [ - parseFloat(m[1]), - parseFloat(m[2]), - parseFloat(m[3]), - ]; - if (isNaN(comps[0]) || isNaN(comps[1]) || isNaN(comps[2])) { - return null; - } - return comps; - } - function createObjectRgbColorParser(type) { - return (text) => { - const comps = parseObjectRgbColorComponents(text); - return comps ? createColor(comps, 'rgb', type) : null; - }; - } - function parseObjectRgbaColorComponents(text) { - const m = text.match(/^\{\s*r\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*g\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*b\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*a\s*:\s*([0-9A-Fa-f.]+%?)\s*\}$/); - if (!m) { - return null; - } - const comps = [ - parseFloat(m[1]), - parseFloat(m[2]), - parseFloat(m[3]), - parseFloat(m[4]), - ]; - if (isNaN(comps[0]) || - isNaN(comps[1]) || - isNaN(comps[2]) || - isNaN(comps[3])) { - return null; - } - return comps; - } - function createObjectRgbaColorParser(type) { - return (text) => { - const comps = parseObjectRgbaColorComponents(text); - return comps ? createColor(comps, 'rgb', type) : null; - }; - } - const PARSER_AND_RESULT = [ - { - parser: parseHexRgbColorComponents, - result: { - alpha: false, - mode: 'rgb', - notation: 'hex', - }, - }, - { - parser: parseHexRgbaColorComponents, - result: { - alpha: true, - mode: 'rgb', - notation: 'hex', - }, - }, - { - parser: parseFunctionalRgbColorComponents, - result: { - alpha: false, - mode: 'rgb', - notation: 'func', - }, - }, - { - parser: parseFunctionalRgbaColorComponents, - result: { - alpha: true, - mode: 'rgb', - notation: 'func', - }, - }, - { - parser: parseFunctionalHslColorComponents, - result: { - alpha: false, - mode: 'hsl', - notation: 'func', - }, - }, - { - parser: parseHslaColorComponents, - result: { - alpha: true, - mode: 'hsl', - notation: 'func', - }, - }, - { - parser: parseObjectRgbColorComponents, - result: { - alpha: false, - mode: 'rgb', - notation: 'object', - }, - }, - { - parser: parseObjectRgbaColorComponents, - result: { - alpha: true, - mode: 'rgb', - notation: 'object', - }, - }, - ]; - function detectStringColor(text) { - return PARSER_AND_RESULT.reduce((prev, { parser, result: detection }) => { - if (prev) { - return prev; - } - return parser(text) ? detection : null; - }, null); - } - function detectStringColorFormat(text, type = 'int') { - const r = detectStringColor(text); - if (!r) { - return null; - } - if (r.notation === 'hex' && type !== 'float') { - return Object.assign(Object.assign({}, r), { type: 'int' }); - } - if (r.notation === 'func') { - return Object.assign(Object.assign({}, r), { type: type }); - } - return null; - } - function createColorStringParser(type) { - const parsers = [ - parseHexRgbColor, - parseHexRgbaColor, - parseFunctionalRgbColor, - parseFunctionalRgbaColor, - parseFunctionalHslColor, - parseFunctionalHslaColor, - ]; - if (type === 'int') { - parsers.push(createObjectRgbColorParser('int'), createObjectRgbaColorParser('int')); - } - if (type === 'float') { - parsers.push(createObjectRgbColorParser('float'), createObjectRgbaColorParser('float')); - } - const parser = composeParsers(parsers); - return (text) => { - const result = parser(text); - return result ? mapColorType(result, type) : null; - }; - } - function readIntColorString(value) { - const parser = createColorStringParser('int'); - if (typeof value !== 'string') { - return IntColor.black(); - } - const result = parser(value); - return result !== null && result !== void 0 ? result : IntColor.black(); - } - function zerofill(comp) { - const hex = constrainRange(Math.floor(comp), 0, 255).toString(16); - return hex.length === 1 ? `0${hex}` : hex; - } - function colorToHexRgbString(value, prefix = '#') { - const hexes = removeAlphaComponent(value.getComponents('rgb')) - .map(zerofill) - .join(''); - return `${prefix}${hexes}`; - } - function colorToHexRgbaString(value, prefix = '#') { - const rgbaComps = value.getComponents('rgb'); - const hexes = [rgbaComps[0], rgbaComps[1], rgbaComps[2], rgbaComps[3] * 255] - .map(zerofill) - .join(''); - return `${prefix}${hexes}`; - } - function colorToFunctionalRgbString(value) { - const formatter = createNumberFormatter(0); - const ci = mapColorType(value, 'int'); - const comps = removeAlphaComponent(ci.getComponents('rgb')).map((comp) => formatter(comp)); - return `rgb(${comps.join(', ')})`; - } - function colorToFunctionalRgbaString(value) { - const aFormatter = createNumberFormatter(2); - const rgbFormatter = createNumberFormatter(0); - const ci = mapColorType(value, 'int'); - const comps = ci.getComponents('rgb').map((comp, index) => { - const formatter = index === 3 ? aFormatter : rgbFormatter; - return formatter(comp); - }); - return `rgba(${comps.join(', ')})`; - } - function colorToFunctionalHslString(value) { - const formatters = [ - createNumberFormatter(0), - formatPercentage, - formatPercentage, - ]; - const ci = mapColorType(value, 'int'); - const comps = removeAlphaComponent(ci.getComponents('hsl')).map((comp, index) => formatters[index](comp)); - return `hsl(${comps.join(', ')})`; - } - function colorToFunctionalHslaString(value) { - const formatters = [ - createNumberFormatter(0), - formatPercentage, - formatPercentage, - createNumberFormatter(2), - ]; - const ci = mapColorType(value, 'int'); - const comps = ci - .getComponents('hsl') - .map((comp, index) => formatters[index](comp)); - return `hsla(${comps.join(', ')})`; - } - function colorToObjectRgbString(value, type) { - const formatter = createNumberFormatter(type === 'float' ? 2 : 0); - const names = ['r', 'g', 'b']; - const cc = mapColorType(value, type); - const comps = removeAlphaComponent(cc.getComponents('rgb')).map((comp, index) => `${names[index]}: ${formatter(comp)}`); - return `{${comps.join(', ')}}`; - } - function createObjectRgbColorFormatter(type) { - return (value) => colorToObjectRgbString(value, type); - } - function colorToObjectRgbaString(value, type) { - const aFormatter = createNumberFormatter(2); - const rgbFormatter = createNumberFormatter(type === 'float' ? 2 : 0); - const names = ['r', 'g', 'b', 'a']; - const cc = mapColorType(value, type); - const comps = cc.getComponents('rgb').map((comp, index) => { - const formatter = index === 3 ? aFormatter : rgbFormatter; - return `${names[index]}: ${formatter(comp)}`; - }); - return `{${comps.join(', ')}}`; - } - function createObjectRgbaColorFormatter(type) { - return (value) => colorToObjectRgbaString(value, type); - } - const FORMAT_AND_STRINGIFIERS = [ - { - format: { - alpha: false, - mode: 'rgb', - notation: 'hex', - type: 'int', - }, - stringifier: colorToHexRgbString, - }, - { - format: { - alpha: true, - mode: 'rgb', - notation: 'hex', - type: 'int', - }, - stringifier: colorToHexRgbaString, - }, - { - format: { - alpha: false, - mode: 'rgb', - notation: 'func', - type: 'int', - }, - stringifier: colorToFunctionalRgbString, - }, - { - format: { - alpha: true, - mode: 'rgb', - notation: 'func', - type: 'int', - }, - stringifier: colorToFunctionalRgbaString, - }, - { - format: { - alpha: false, - mode: 'hsl', - notation: 'func', - type: 'int', - }, - stringifier: colorToFunctionalHslString, - }, - { - format: { - alpha: true, - mode: 'hsl', - notation: 'func', - type: 'int', - }, - stringifier: colorToFunctionalHslaString, - }, - ...['int', 'float'].reduce((prev, type) => { - return [ - ...prev, - { - format: { - alpha: false, - mode: 'rgb', - notation: 'object', - type: type, - }, - stringifier: createObjectRgbColorFormatter(type), - }, - { - format: { - alpha: true, - mode: 'rgb', - notation: 'object', - type: type, - }, - stringifier: createObjectRgbaColorFormatter(type), - }, - ]; - }, []), - ]; - function findColorStringifier(format) { - return FORMAT_AND_STRINGIFIERS.reduce((prev, fas) => { - if (prev) { - return prev; - } - return equalsStringColorFormat(fas.format, format) - ? fas.stringifier - : null; - }, null); - } - - const cn$a = ClassName('apl'); - class APaletteView { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.value = config.value; - this.value.emitter.on('change', this.onValueChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$a()); - config.viewProps.bindClassModifiers(this.element); - config.viewProps.bindTabIndex(this.element); - const barElem = doc.createElement('div'); - barElem.classList.add(cn$a('b')); - this.element.appendChild(barElem); - const colorElem = doc.createElement('div'); - colorElem.classList.add(cn$a('c')); - barElem.appendChild(colorElem); - this.colorElem_ = colorElem; - const markerElem = doc.createElement('div'); - markerElem.classList.add(cn$a('m')); - this.element.appendChild(markerElem); - this.markerElem_ = markerElem; - const previewElem = doc.createElement('div'); - previewElem.classList.add(cn$a('p')); - this.markerElem_.appendChild(previewElem); - this.previewElem_ = previewElem; - this.update_(); - } - update_() { - const c = this.value.rawValue; - const rgbaComps = c.getComponents('rgb'); - const leftColor = new IntColor([rgbaComps[0], rgbaComps[1], rgbaComps[2], 0], 'rgb'); - const rightColor = new IntColor([rgbaComps[0], rgbaComps[1], rgbaComps[2], 255], 'rgb'); - const gradientComps = [ - 'to right', - colorToFunctionalRgbaString(leftColor), - colorToFunctionalRgbaString(rightColor), - ]; - this.colorElem_.style.background = `linear-gradient(${gradientComps.join(',')})`; - this.previewElem_.style.backgroundColor = colorToFunctionalRgbaString(c); - const left = mapRange(rgbaComps[3], 0, 1, 0, 100); - this.markerElem_.style.left = `${left}%`; - } - onValueChange_() { - this.update_(); - } - } - - class APaletteController { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new APaletteView(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler(this.view.element); - this.ptHandler_.emitter.on('down', this.onPointerDown_); - this.ptHandler_.emitter.on('move', this.onPointerMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.element.addEventListener('keydown', this.onKeyDown_); - this.view.element.addEventListener('keyup', this.onKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - const alpha = d.point.x / d.bounds.width; - const c = this.value.rawValue; - const [h, s, v] = c.getComponents('hsv'); - this.value.setRawValue(new IntColor([h, s, v, alpha], 'hsv'), opts); - } - onPointerDown_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - const step = getStepForKey(getKeyScaleForColor(true), getHorizontalStepKeys(ev)); - if (step === 0) { - return; - } - const c = this.value.rawValue; - const [h, s, v, a] = c.getComponents('hsv'); - this.value.setRawValue(new IntColor([h, s, v, a + step], 'hsv'), { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - const step = getStepForKey(getKeyScaleForColor(true), getHorizontalStepKeys(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - const cn$9 = ClassName('coltxt'); - function createModeSelectElement(doc) { - const selectElem = doc.createElement('select'); - const items = [ - { text: 'RGB', value: 'rgb' }, - { text: 'HSL', value: 'hsl' }, - { text: 'HSV', value: 'hsv' }, - { text: 'HEX', value: 'hex' }, - ]; - selectElem.appendChild(items.reduce((frag, item) => { - const optElem = doc.createElement('option'); - optElem.textContent = item.text; - optElem.value = item.value; - frag.appendChild(optElem); - return frag; - }, doc.createDocumentFragment())); - return selectElem; - } - class ColorTextsView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$9()); - config.viewProps.bindClassModifiers(this.element); - const modeElem = doc.createElement('div'); - modeElem.classList.add(cn$9('m')); - this.modeElem_ = createModeSelectElement(doc); - this.modeElem_.classList.add(cn$9('ms')); - modeElem.appendChild(this.modeSelectElement); - config.viewProps.bindDisabled(this.modeElem_); - const modeMarkerElem = doc.createElement('div'); - modeMarkerElem.classList.add(cn$9('mm')); - modeMarkerElem.appendChild(createSvgIconElement(doc, 'dropdown')); - modeElem.appendChild(modeMarkerElem); - this.element.appendChild(modeElem); - const inputsElem = doc.createElement('div'); - inputsElem.classList.add(cn$9('w')); - this.element.appendChild(inputsElem); - this.inputsElem_ = inputsElem; - this.inputViews_ = config.inputViews; - this.applyInputViews_(); - bindValue(config.mode, (mode) => { - this.modeElem_.value = mode; - }); - } - get modeSelectElement() { - return this.modeElem_; - } - get inputViews() { - return this.inputViews_; - } - set inputViews(inputViews) { - this.inputViews_ = inputViews; - this.applyInputViews_(); - } - applyInputViews_() { - removeChildElements(this.inputsElem_); - const doc = this.element.ownerDocument; - this.inputViews_.forEach((v) => { - const compElem = doc.createElement('div'); - compElem.classList.add(cn$9('c')); - compElem.appendChild(v.element); - this.inputsElem_.appendChild(compElem); - }); - } - } - - function createFormatter$2(type) { - return createNumberFormatter(type === 'float' ? 2 : 0); - } - function createConstraint$7(mode, type, index) { - const max = getColorMaxComponents(mode, type)[index]; - return new DefiniteRangeConstraint({ - min: 0, - max: max, - }); - } - function createComponentController(doc, config, index) { - return new NumberTextController(doc, { - arrayPosition: index === 0 ? 'fst' : index === 3 - 1 ? 'lst' : 'mid', - parser: config.parser, - props: ValueMap.fromObject({ - formatter: createFormatter$2(config.colorType), - keyScale: getKeyScaleForColor(false), - pointerScale: config.colorType === 'float' ? 0.01 : 1, - }), - value: createValue(0, { - constraint: createConstraint$7(config.colorMode, config.colorType, index), - }), - viewProps: config.viewProps, - }); - } - function createComponentControllers(doc, config) { - const cc = { - colorMode: config.colorMode, - colorType: config.colorType, - parser: parseNumber, - viewProps: config.viewProps, - }; - return [0, 1, 2].map((i) => { - const c = createComponentController(doc, cc, i); - connectValues({ - primary: config.value, - secondary: c.value, - forward(p) { - const mc = mapColorType(p, config.colorType); - return mc.getComponents(config.colorMode)[i]; - }, - backward(p, s) { - const pickedMode = config.colorMode; - const mc = mapColorType(p, config.colorType); - const comps = mc.getComponents(pickedMode); - comps[i] = s; - const c = createColor(appendAlphaComponent(removeAlphaComponent(comps), comps[3]), pickedMode, config.colorType); - return mapColorType(c, 'int'); - }, - }); - return c; - }); - } - function createHexController(doc, config) { - const c = new TextController(doc, { - parser: createColorStringParser('int'), - props: ValueMap.fromObject({ - formatter: colorToHexRgbString, - }), - value: createValue(IntColor.black()), - viewProps: config.viewProps, - }); - connectValues({ - primary: config.value, - secondary: c.value, - forward: (p) => new IntColor(removeAlphaComponent(p.getComponents()), p.mode), - backward: (p, s) => new IntColor(appendAlphaComponent(removeAlphaComponent(s.getComponents(p.mode)), p.getComponents()[3]), p.mode), - }); - return [c]; - } - function isColorMode(mode) { - return mode !== 'hex'; - } - class ColorTextsController { - constructor(doc, config) { - this.onModeSelectChange_ = this.onModeSelectChange_.bind(this); - this.colorType_ = config.colorType; - this.value = config.value; - this.viewProps = config.viewProps; - this.colorMode = createValue(this.value.rawValue.mode); - this.ccs_ = this.createComponentControllers_(doc); - this.view = new ColorTextsView(doc, { - mode: this.colorMode, - inputViews: [this.ccs_[0].view, this.ccs_[1].view, this.ccs_[2].view], - viewProps: this.viewProps, - }); - this.view.modeSelectElement.addEventListener('change', this.onModeSelectChange_); - } - createComponentControllers_(doc) { - const mode = this.colorMode.rawValue; - if (isColorMode(mode)) { - return createComponentControllers(doc, { - colorMode: mode, - colorType: this.colorType_, - value: this.value, - viewProps: this.viewProps, - }); - } - return createHexController(doc, { - value: this.value, - viewProps: this.viewProps, - }); - } - onModeSelectChange_(ev) { - const selectElem = ev.currentTarget; - this.colorMode.rawValue = selectElem.value; - this.ccs_ = this.createComponentControllers_(this.view.element.ownerDocument); - this.view.inputViews = this.ccs_.map((cc) => cc.view); - } - } - - const cn$8 = ClassName('hpl'); - class HPaletteView { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.value = config.value; - this.value.emitter.on('change', this.onValueChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$8()); - config.viewProps.bindClassModifiers(this.element); - config.viewProps.bindTabIndex(this.element); - const colorElem = doc.createElement('div'); - colorElem.classList.add(cn$8('c')); - this.element.appendChild(colorElem); - const markerElem = doc.createElement('div'); - markerElem.classList.add(cn$8('m')); - this.element.appendChild(markerElem); - this.markerElem_ = markerElem; - this.update_(); - } - update_() { - const c = this.value.rawValue; - const [h] = c.getComponents('hsv'); - this.markerElem_.style.backgroundColor = colorToFunctionalRgbString(new IntColor([h, 100, 100], 'hsv')); - const left = mapRange(h, 0, 360, 0, 100); - this.markerElem_.style.left = `${left}%`; - } - onValueChange_() { - this.update_(); - } - } - - class HPaletteController { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new HPaletteView(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler(this.view.element); - this.ptHandler_.emitter.on('down', this.onPointerDown_); - this.ptHandler_.emitter.on('move', this.onPointerMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.element.addEventListener('keydown', this.onKeyDown_); - this.view.element.addEventListener('keyup', this.onKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - const hue = mapRange(constrainRange(d.point.x, 0, d.bounds.width), 0, d.bounds.width, 0, 360); - const c = this.value.rawValue; - const [, s, v, a] = c.getComponents('hsv'); - this.value.setRawValue(new IntColor([hue, s, v, a], 'hsv'), opts); - } - onPointerDown_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - const step = getStepForKey(getKeyScaleForColor(false), getHorizontalStepKeys(ev)); - if (step === 0) { - return; - } - const c = this.value.rawValue; - const [h, s, v, a] = c.getComponents('hsv'); - this.value.setRawValue(new IntColor([h + step, s, v, a], 'hsv'), { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - const step = getStepForKey(getKeyScaleForColor(false), getHorizontalStepKeys(ev)); - if (step === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - const cn$7 = ClassName('svp'); - const CANVAS_RESOL = 64; - class SvPaletteView { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - this.value = config.value; - this.value.emitter.on('change', this.onValueChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$7()); - config.viewProps.bindClassModifiers(this.element); - config.viewProps.bindTabIndex(this.element); - const canvasElem = doc.createElement('canvas'); - canvasElem.height = CANVAS_RESOL; - canvasElem.width = CANVAS_RESOL; - canvasElem.classList.add(cn$7('c')); - this.element.appendChild(canvasElem); - this.canvasElement = canvasElem; - const markerElem = doc.createElement('div'); - markerElem.classList.add(cn$7('m')); - this.element.appendChild(markerElem); - this.markerElem_ = markerElem; - this.update_(); - } - update_() { - const ctx = getCanvasContext(this.canvasElement); - if (!ctx) { - return; - } - const c = this.value.rawValue; - const hsvComps = c.getComponents('hsv'); - const width = this.canvasElement.width; - const height = this.canvasElement.height; - const imgData = ctx.getImageData(0, 0, width, height); - const data = imgData.data; - for (let iy = 0; iy < height; iy++) { - for (let ix = 0; ix < width; ix++) { - const s = mapRange(ix, 0, width, 0, 100); - const v = mapRange(iy, 0, height, 100, 0); - const rgbComps = hsvToRgbInt(hsvComps[0], s, v); - const i = (iy * width + ix) * 4; - data[i] = rgbComps[0]; - data[i + 1] = rgbComps[1]; - data[i + 2] = rgbComps[2]; - data[i + 3] = 255; - } - } - ctx.putImageData(imgData, 0, 0); - const left = mapRange(hsvComps[1], 0, 100, 0, 100); - this.markerElem_.style.left = `${left}%`; - const top = mapRange(hsvComps[2], 0, 100, 100, 0); - this.markerElem_.style.top = `${top}%`; - } - onValueChange_() { - this.update_(); - } - } - - class SvPaletteController { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new SvPaletteView(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler(this.view.element); - this.ptHandler_.emitter.on('down', this.onPointerDown_); - this.ptHandler_.emitter.on('move', this.onPointerMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.element.addEventListener('keydown', this.onKeyDown_); - this.view.element.addEventListener('keyup', this.onKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - const saturation = mapRange(d.point.x, 0, d.bounds.width, 0, 100); - const value = mapRange(d.point.y, 0, d.bounds.height, 100, 0); - const [h, , , a] = this.value.rawValue.getComponents('hsv'); - this.value.setRawValue(new IntColor([h, saturation, value, a], 'hsv'), opts); - } - onPointerDown_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - if (isArrowKey(ev.key)) { - ev.preventDefault(); - } - const [h, s, v, a] = this.value.rawValue.getComponents('hsv'); - const keyScale = getKeyScaleForColor(false); - const ds = getStepForKey(keyScale, getHorizontalStepKeys(ev)); - const dv = getStepForKey(keyScale, getVerticalStepKeys(ev)); - if (ds === 0 && dv === 0) { - return; - } - this.value.setRawValue(new IntColor([h, s + ds, v + dv, a], 'hsv'), { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - const keyScale = getKeyScaleForColor(false); - const ds = getStepForKey(keyScale, getHorizontalStepKeys(ev)); - const dv = getStepForKey(keyScale, getVerticalStepKeys(ev)); - if (ds === 0 && dv === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - class ColorPickerController { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.hPaletteC_ = new HPaletteController(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.svPaletteC_ = new SvPaletteController(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.alphaIcs_ = config.supportsAlpha - ? { - palette: new APaletteController(doc, { - value: this.value, - viewProps: this.viewProps, - }), - text: new NumberTextController(doc, { - parser: parseNumber, - props: ValueMap.fromObject({ - pointerScale: 0.01, - keyScale: 0.1, - formatter: createNumberFormatter(2), - }), - value: createValue(0, { - constraint: new DefiniteRangeConstraint({ min: 0, max: 1 }), - }), - viewProps: this.viewProps, - }), - } - : null; - if (this.alphaIcs_) { - connectValues({ - primary: this.value, - secondary: this.alphaIcs_.text.value, - forward: (p) => p.getComponents()[3], - backward: (p, s) => { - const comps = p.getComponents(); - comps[3] = s; - return new IntColor(comps, p.mode); - }, - }); - } - this.textsC_ = new ColorTextsController(doc, { - colorType: config.colorType, - value: this.value, - viewProps: this.viewProps, - }); - this.view = new ColorPickerView(doc, { - alphaViews: this.alphaIcs_ - ? { - palette: this.alphaIcs_.palette.view, - text: this.alphaIcs_.text.view, - } - : null, - hPaletteView: this.hPaletteC_.view, - supportsAlpha: config.supportsAlpha, - svPaletteView: this.svPaletteC_.view, - textsView: this.textsC_.view, - viewProps: this.viewProps, - }); - } - get textsController() { - return this.textsC_; - } - } - - const cn$6 = ClassName('colsw'); - class ColorSwatchView { - constructor(doc, config) { - this.onValueChange_ = this.onValueChange_.bind(this); - config.value.emitter.on('change', this.onValueChange_); - this.value = config.value; - this.element = doc.createElement('div'); - this.element.classList.add(cn$6()); - config.viewProps.bindClassModifiers(this.element); - const swatchElem = doc.createElement('div'); - swatchElem.classList.add(cn$6('sw')); - this.element.appendChild(swatchElem); - this.swatchElem_ = swatchElem; - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(cn$6('b')); - config.viewProps.bindDisabled(buttonElem); - this.element.appendChild(buttonElem); - this.buttonElement = buttonElem; - this.update_(); - } - update_() { - const value = this.value.rawValue; - this.swatchElem_.style.backgroundColor = colorToHexRgbaString(value); - } - onValueChange_() { - this.update_(); - } - } - - class ColorSwatchController { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new ColorSwatchView(doc, { - value: this.value, - viewProps: this.viewProps, - }); - } - } - - class ColorController { - constructor(doc, config) { - this.onButtonBlur_ = this.onButtonBlur_.bind(this); - this.onButtonClick_ = this.onButtonClick_.bind(this); - this.onPopupChildBlur_ = this.onPopupChildBlur_.bind(this); - this.onPopupChildKeydown_ = this.onPopupChildKeydown_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.foldable_ = Foldable.create(config.expanded); - this.swatchC_ = new ColorSwatchController(doc, { - value: this.value, - viewProps: this.viewProps, - }); - const buttonElem = this.swatchC_.view.buttonElement; - buttonElem.addEventListener('blur', this.onButtonBlur_); - buttonElem.addEventListener('click', this.onButtonClick_); - this.textC_ = new TextController(doc, { - parser: config.parser, - props: ValueMap.fromObject({ - formatter: config.formatter, - }), - value: this.value, - viewProps: this.viewProps, - }); - this.view = new ColorView(doc, { - foldable: this.foldable_, - pickerLayout: config.pickerLayout, - }); - this.view.swatchElement.appendChild(this.swatchC_.view.element); - this.view.textElement.appendChild(this.textC_.view.element); - this.popC_ = - config.pickerLayout === 'popup' - ? new PopupController(doc, { - viewProps: this.viewProps, - }) - : null; - const pickerC = new ColorPickerController(doc, { - colorType: config.colorType, - supportsAlpha: config.supportsAlpha, - value: this.value, - viewProps: this.viewProps, - }); - pickerC.view.allFocusableElements.forEach((elem) => { - elem.addEventListener('blur', this.onPopupChildBlur_); - elem.addEventListener('keydown', this.onPopupChildKeydown_); - }); - this.pickerC_ = pickerC; - if (this.popC_) { - this.view.element.appendChild(this.popC_.view.element); - this.popC_.view.element.appendChild(pickerC.view.element); - connectValues({ - primary: this.foldable_.value('expanded'), - secondary: this.popC_.shows, - forward: (p) => p, - backward: (_, s) => s, - }); - } - else if (this.view.pickerElement) { - this.view.pickerElement.appendChild(this.pickerC_.view.element); - bindFoldable(this.foldable_, this.view.pickerElement); - } - } - get textController() { - return this.textC_; - } - onButtonBlur_(e) { - if (!this.popC_) { - return; - } - const elem = this.view.element; - const nextTarget = forceCast(e.relatedTarget); - if (!nextTarget || !elem.contains(nextTarget)) { - this.popC_.shows.rawValue = false; - } - } - onButtonClick_() { - this.foldable_.set('expanded', !this.foldable_.get('expanded')); - if (this.foldable_.get('expanded')) { - this.pickerC_.view.allFocusableElements[0].focus(); - } - } - onPopupChildBlur_(ev) { - if (!this.popC_) { - return; - } - const elem = this.popC_.view.element; - const nextTarget = findNextTarget(ev); - if (nextTarget && elem.contains(nextTarget)) { - return; - } - if (nextTarget && - nextTarget === this.swatchC_.view.buttonElement && - !supportsTouch(elem.ownerDocument)) { - return; - } - this.popC_.shows.rawValue = false; - } - onPopupChildKeydown_(ev) { - if (this.popC_) { - if (ev.key === 'Escape') { - this.popC_.shows.rawValue = false; - } - } - else if (this.view.pickerElement) { - if (ev.key === 'Escape') { - this.swatchC_.view.buttonElement.focus(); - } - } - } - } - - function colorToRgbNumber(value) { - return removeAlphaComponent(value.getComponents('rgb')).reduce((result, comp) => { - return (result << 8) | (Math.floor(comp) & 0xff); - }, 0); - } - function colorToRgbaNumber(value) { - return (value.getComponents('rgb').reduce((result, comp, index) => { - const hex = Math.floor(index === 3 ? comp * 255 : comp) & 0xff; - return (result << 8) | hex; - }, 0) >>> 0); - } - function numberToRgbColor(num) { - return new IntColor([(num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff], 'rgb'); - } - function numberToRgbaColor(num) { - return new IntColor([ - (num >> 24) & 0xff, - (num >> 16) & 0xff, - (num >> 8) & 0xff, - mapRange(num & 0xff, 0, 255, 0, 1), - ], 'rgb'); - } - function colorFromRgbNumber(value) { - if (typeof value !== 'number') { - return IntColor.black(); - } - return numberToRgbColor(value); - } - function colorFromRgbaNumber(value) { - if (typeof value !== 'number') { - return IntColor.black(); - } - return numberToRgbaColor(value); - } - - function isRgbColorComponent(obj, key) { - if (typeof obj !== 'object' || isEmpty(obj)) { - return false; - } - return key in obj && typeof obj[key] === 'number'; - } - function isRgbColorObject(obj) { - return (isRgbColorComponent(obj, 'r') && - isRgbColorComponent(obj, 'g') && - isRgbColorComponent(obj, 'b')); - } - function isRgbaColorObject(obj) { - return isRgbColorObject(obj) && isRgbColorComponent(obj, 'a'); - } - function isColorObject(obj) { - return isRgbColorObject(obj); - } - function equalsColor(v1, v2) { - if (v1.mode !== v2.mode) { - return false; - } - if (v1.type !== v2.type) { - return false; - } - const comps1 = v1.getComponents(); - const comps2 = v2.getComponents(); - for (let i = 0; i < comps1.length; i++) { - if (comps1[i] !== comps2[i]) { - return false; - } - } - return true; - } - function createColorComponentsFromRgbObject(obj) { - return 'a' in obj ? [obj.r, obj.g, obj.b, obj.a] : [obj.r, obj.g, obj.b]; - } - - function createColorStringWriter(format) { - const stringify = findColorStringifier(format); - return stringify - ? (target, value) => { - writePrimitive(target, stringify(value)); - } - : null; - } - function createColorNumberWriter(supportsAlpha) { - const colorToNumber = supportsAlpha ? colorToRgbaNumber : colorToRgbNumber; - return (target, value) => { - writePrimitive(target, colorToNumber(value)); - }; - } - function writeRgbaColorObject(target, value, type) { - const cc = mapColorType(value, type); - const obj = cc.toRgbaObject(); - target.writeProperty('r', obj.r); - target.writeProperty('g', obj.g); - target.writeProperty('b', obj.b); - target.writeProperty('a', obj.a); - } - function writeRgbColorObject(target, value, type) { - const cc = mapColorType(value, type); - const obj = cc.toRgbaObject(); - target.writeProperty('r', obj.r); - target.writeProperty('g', obj.g); - target.writeProperty('b', obj.b); - } - function createColorObjectWriter(supportsAlpha, type) { - return (target, inValue) => { - if (supportsAlpha) { - writeRgbaColorObject(target, inValue, type); - } - else { - writeRgbColorObject(target, inValue, type); - } - }; - } - - function shouldSupportAlpha$1(inputParams) { - var _a; - if ((_a = inputParams === null || inputParams === void 0 ? void 0 : inputParams.color) === null || _a === void 0 ? void 0 : _a.alpha) { - return true; - } - return false; - } - function createFormatter$1(supportsAlpha) { - return supportsAlpha - ? (v) => colorToHexRgbaString(v, '0x') - : (v) => colorToHexRgbString(v, '0x'); - } - function isForColor(params) { - if ('color' in params) { - return true; - } - if (params.view === 'color') { - return true; - } - return false; - } - createPlugin({ - id: 'input-color-number', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'number') { - return null; - } - if (!isForColor(params)) { - return null; - } - const result = parseColorInputParams(params); - return result - ? { - initialValue: value, - params: Object.assign(Object.assign({}, result), { supportsAlpha: shouldSupportAlpha$1(params) }), - } - : null; - }, - binding: { - reader: (args) => { - return args.params.supportsAlpha - ? colorFromRgbaNumber - : colorFromRgbNumber; - }, - equals: equalsColor, - writer: (args) => { - return createColorNumberWriter(args.params.supportsAlpha); - }, - }, - controller: (args) => { - var _a, _b; - return new ColorController(args.document, { - colorType: 'int', - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - formatter: createFormatter$1(args.params.supportsAlpha), - parser: createColorStringParser('int'), - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - supportsAlpha: args.params.supportsAlpha, - value: args.value, - viewProps: args.viewProps, - }); - }, - }); - - function colorFromObject(value, type) { - if (!isColorObject(value)) { - return mapColorType(IntColor.black(), type); - } - if (type === 'int') { - const comps = createColorComponentsFromRgbObject(value); - return new IntColor(comps, 'rgb'); - } - if (type === 'float') { - const comps = createColorComponentsFromRgbObject(value); - return new FloatColor(comps, 'rgb'); - } - return mapColorType(IntColor.black(), 'int'); - } - - function shouldSupportAlpha(initialValue) { - return isRgbaColorObject(initialValue); - } - function createColorObjectBindingReader(type) { - return (value) => { - const c = colorFromObject(value, type); - return mapColorType(c, 'int'); - }; - } - function createColorObjectFormatter(supportsAlpha, type) { - return (value) => { - if (supportsAlpha) { - return colorToObjectRgbaString(value, type); - } - return colorToObjectRgbString(value, type); - }; - } - createPlugin({ - id: 'input-color-object', - type: 'input', - accept: (value, params) => { - var _a; - if (!isColorObject(value)) { - return null; - } - const result = parseColorInputParams(params); - return result - ? { - initialValue: value, - params: Object.assign(Object.assign({}, result), { colorType: (_a = extractColorType(params)) !== null && _a !== void 0 ? _a : 'int' }), - } - : null; - }, - binding: { - reader: (args) => createColorObjectBindingReader(args.params.colorType), - equals: equalsColor, - writer: (args) => createColorObjectWriter(shouldSupportAlpha(args.initialValue), args.params.colorType), - }, - controller: (args) => { - var _a, _b; - const supportsAlpha = isRgbaColorObject(args.initialValue); - return new ColorController(args.document, { - colorType: args.params.colorType, - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - formatter: createColorObjectFormatter(supportsAlpha, args.params.colorType), - parser: createColorStringParser('int'), - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - supportsAlpha: supportsAlpha, - value: args.value, - viewProps: args.viewProps, - }); - }, - }); - - createPlugin({ - id: 'input-color-string', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'string') { - return null; - } - if (params.view === 'text') { - return null; - } - const format = detectStringColorFormat(value, extractColorType(params)); - if (!format) { - return null; - } - const stringifier = findColorStringifier(format); - if (!stringifier) { - return null; - } - const result = parseColorInputParams(params); - return result - ? { - initialValue: value, - params: Object.assign(Object.assign({}, result), { format: format, stringifier: stringifier }), - } - : null; - }, - binding: { - reader: () => readIntColorString, - equals: equalsColor, - writer: (args) => { - const writer = createColorStringWriter(args.params.format); - if (!writer) { - throw TpError.notBindable(); - } - return writer; - }, - }, - controller: (args) => { - var _a, _b; - return new ColorController(args.document, { - colorType: args.params.format.type, - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - formatter: args.params.stringifier, - parser: createColorStringParser('int'), - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - supportsAlpha: args.params.format.alpha, - value: args.value, - viewProps: args.viewProps, - }); - }, - }); - - class PointNdConstraint { - constructor(config) { - this.components = config.components; - this.asm_ = config.assembly; - } - constrain(value) { - const comps = this.asm_ - .toComponents(value) - .map((comp, index) => { var _a, _b; return (_b = (_a = this.components[index]) === null || _a === void 0 ? void 0 : _a.constrain(comp)) !== null && _b !== void 0 ? _b : comp; }); - return this.asm_.fromComponents(comps); - } - } - - const cn$5 = ClassName('pndtxt'); - class PointNdTextView { - constructor(doc, config) { - this.textViews = config.textViews; - this.element = doc.createElement('div'); - this.element.classList.add(cn$5()); - this.textViews.forEach((v) => { - const axisElem = doc.createElement('div'); - axisElem.classList.add(cn$5('a')); - axisElem.appendChild(v.element); - this.element.appendChild(axisElem); - }); - } - } - - function createAxisController(doc, config, index) { - return new NumberTextController(doc, { - arrayPosition: index === 0 ? 'fst' : index === config.axes.length - 1 ? 'lst' : 'mid', - parser: config.parser, - props: config.axes[index].textProps, - value: createValue(0, { - constraint: config.axes[index].constraint, - }), - viewProps: config.viewProps, - }); - } - class PointNdTextController { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.acs_ = config.axes.map((_, index) => createAxisController(doc, config, index)); - this.acs_.forEach((c, index) => { - connectValues({ - primary: this.value, - secondary: c.value, - forward: (p) => config.assembly.toComponents(p)[index], - backward: (p, s) => { - const comps = config.assembly.toComponents(p); - comps[index] = s; - return config.assembly.fromComponents(comps); - }, - }); - }); - this.view = new PointNdTextView(doc, { - textViews: this.acs_.map((ac) => ac.view), - }); - } - get textControllers() { - return this.acs_; - } - } - - class SliderInputBindingApi extends BindingApi { - get max() { - return this.controller.valueController.sliderController.props.get('max'); - } - set max(max) { - this.controller.valueController.sliderController.props.set('max', max); - } - get min() { - return this.controller.valueController.sliderController.props.get('min'); - } - set min(max) { - this.controller.valueController.sliderController.props.set('min', max); - } - } - - function createConstraint$6(params, initialValue) { - const constraints = []; - const sc = createStepConstraint(params, initialValue); - if (sc) { - constraints.push(sc); - } - const rc = createRangeConstraint(params); - if (rc) { - constraints.push(rc); - } - const lc = createListConstraint(params.options); - if (lc) { - constraints.push(lc); - } - return new CompositeConstraint(constraints); - } - createPlugin({ - id: 'input-number', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'number') { - return null; - } - const result = parseRecord(params, (p) => (Object.assign(Object.assign({}, createNumberTextInputParamsParser(p)), { options: p.optional.custom(parseListOptions), readonly: p.optional.constant(false) }))); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => numberFromUnknown, - constraint: (args) => createConstraint$6(args.params, args.initialValue), - writer: (_args) => writePrimitive, - }, - controller: (args) => { - const value = args.value; - const c = args.constraint; - const lc = c && findConstraint(c, ListConstraint); - if (lc) { - return new ListController(args.document, { - props: new ValueMap({ - options: lc.values.value('options'), - }), - value: value, - viewProps: args.viewProps, - }); - } - const textPropsObj = createNumberTextPropsObject(args.params, value.rawValue); - const drc = c && findConstraint(c, DefiniteRangeConstraint); - if (drc) { - return new SliderTextController(args.document, Object.assign(Object.assign({}, createSliderTextProps(Object.assign(Object.assign({}, textPropsObj), { keyScale: createValue(textPropsObj.keyScale), max: drc.values.value('max'), min: drc.values.value('min') }))), { parser: parseNumber, value: value, viewProps: args.viewProps })); - } - return new NumberTextController(args.document, { - parser: parseNumber, - props: ValueMap.fromObject(textPropsObj), - value: value, - viewProps: args.viewProps, - }); - }, - api(args) { - if (typeof args.controller.value.rawValue !== 'number') { - return null; - } - if (args.controller.valueController instanceof SliderTextController) { - return new SliderInputBindingApi(args.controller); - } - if (args.controller.valueController instanceof ListController) { - return new ListInputBindingApi(args.controller); - } - return null; - }, - }); - - class Point2d { - constructor(x = 0, y = 0) { - this.x = x; - this.y = y; - } - getComponents() { - return [this.x, this.y]; - } - static isObject(obj) { - if (isEmpty(obj)) { - return false; - } - const x = obj.x; - const y = obj.y; - if (typeof x !== 'number' || typeof y !== 'number') { - return false; - } - return true; - } - static equals(v1, v2) { - return v1.x === v2.x && v1.y === v2.y; - } - toObject() { - return { - x: this.x, - y: this.y, - }; - } - } - const Point2dAssembly = { - toComponents: (p) => p.getComponents(), - fromComponents: (comps) => new Point2d(...comps), - }; - - const cn$4 = ClassName('p2d'); - class Point2dView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(cn$4()); - config.viewProps.bindClassModifiers(this.element); - bindValue(config.expanded, valueToClassName(this.element, cn$4(undefined, 'expanded'))); - const headElem = doc.createElement('div'); - headElem.classList.add(cn$4('h')); - this.element.appendChild(headElem); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(cn$4('b')); - buttonElem.appendChild(createSvgIconElement(doc, 'p2dpad')); - config.viewProps.bindDisabled(buttonElem); - headElem.appendChild(buttonElem); - this.buttonElement = buttonElem; - const textElem = doc.createElement('div'); - textElem.classList.add(cn$4('t')); - headElem.appendChild(textElem); - this.textElement = textElem; - if (config.pickerLayout === 'inline') { - const pickerElem = doc.createElement('div'); - pickerElem.classList.add(cn$4('p')); - this.element.appendChild(pickerElem); - this.pickerElement = pickerElem; - } - else { - this.pickerElement = null; - } - } - } - - const cn$3 = ClassName('p2dp'); - class Point2dPickerView { - constructor(doc, config) { - this.onFoldableChange_ = this.onFoldableChange_.bind(this); - this.onPropsChange_ = this.onPropsChange_.bind(this); - this.onValueChange_ = this.onValueChange_.bind(this); - this.props_ = config.props; - this.props_.emitter.on('change', this.onPropsChange_); - this.element = doc.createElement('div'); - this.element.classList.add(cn$3()); - if (config.layout === 'popup') { - this.element.classList.add(cn$3(undefined, 'p')); - } - config.viewProps.bindClassModifiers(this.element); - const padElem = doc.createElement('div'); - padElem.classList.add(cn$3('p')); - config.viewProps.bindTabIndex(padElem); - this.element.appendChild(padElem); - this.padElement = padElem; - const svgElem = doc.createElementNS(SVG_NS, 'svg'); - svgElem.classList.add(cn$3('g')); - this.padElement.appendChild(svgElem); - this.svgElem_ = svgElem; - const xAxisElem = doc.createElementNS(SVG_NS, 'line'); - xAxisElem.classList.add(cn$3('ax')); - xAxisElem.setAttributeNS(null, 'x1', '0'); - xAxisElem.setAttributeNS(null, 'y1', '50%'); - xAxisElem.setAttributeNS(null, 'x2', '100%'); - xAxisElem.setAttributeNS(null, 'y2', '50%'); - this.svgElem_.appendChild(xAxisElem); - const yAxisElem = doc.createElementNS(SVG_NS, 'line'); - yAxisElem.classList.add(cn$3('ax')); - yAxisElem.setAttributeNS(null, 'x1', '50%'); - yAxisElem.setAttributeNS(null, 'y1', '0'); - yAxisElem.setAttributeNS(null, 'x2', '50%'); - yAxisElem.setAttributeNS(null, 'y2', '100%'); - this.svgElem_.appendChild(yAxisElem); - const lineElem = doc.createElementNS(SVG_NS, 'line'); - lineElem.classList.add(cn$3('l')); - lineElem.setAttributeNS(null, 'x1', '50%'); - lineElem.setAttributeNS(null, 'y1', '50%'); - this.svgElem_.appendChild(lineElem); - this.lineElem_ = lineElem; - const markerElem = doc.createElement('div'); - markerElem.classList.add(cn$3('m')); - this.padElement.appendChild(markerElem); - this.markerElem_ = markerElem; - config.value.emitter.on('change', this.onValueChange_); - this.value = config.value; - this.update_(); - } - get allFocusableElements() { - return [this.padElement]; - } - update_() { - const [x, y] = this.value.rawValue.getComponents(); - const max = this.props_.get('max'); - const px = mapRange(x, -max, +max, 0, 100); - const py = mapRange(y, -max, +max, 0, 100); - const ipy = this.props_.get('invertsY') ? 100 - py : py; - this.lineElem_.setAttributeNS(null, 'x2', `${px}%`); - this.lineElem_.setAttributeNS(null, 'y2', `${ipy}%`); - this.markerElem_.style.left = `${px}%`; - this.markerElem_.style.top = `${ipy}%`; - } - onValueChange_() { - this.update_(); - } - onPropsChange_() { - this.update_(); - } - onFoldableChange_() { - this.update_(); - } - } - - function computeOffset(ev, keyScales, invertsY) { - return [ - getStepForKey(keyScales[0], getHorizontalStepKeys(ev)), - getStepForKey(keyScales[1], getVerticalStepKeys(ev)) * (invertsY ? 1 : -1), - ]; - } - class Point2dPickerController { - constructor(doc, config) { - this.onPadKeyDown_ = this.onPadKeyDown_.bind(this); - this.onPadKeyUp_ = this.onPadKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.props = config.props; - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new Point2dPickerView(doc, { - layout: config.layout, - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - this.ptHandler_ = new PointerHandler(this.view.padElement); - this.ptHandler_.emitter.on('down', this.onPointerDown_); - this.ptHandler_.emitter.on('move', this.onPointerMove_); - this.ptHandler_.emitter.on('up', this.onPointerUp_); - this.view.padElement.addEventListener('keydown', this.onPadKeyDown_); - this.view.padElement.addEventListener('keyup', this.onPadKeyUp_); - } - handlePointerEvent_(d, opts) { - if (!d.point) { - return; - } - const max = this.props.get('max'); - const px = mapRange(d.point.x, 0, d.bounds.width, -max, +max); - const py = mapRange(this.props.get('invertsY') ? d.bounds.height - d.point.y : d.point.y, 0, d.bounds.height, -max, +max); - this.value.setRawValue(new Point2d(px, py), opts); - } - onPointerDown_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.handlePointerEvent_(ev.data, { - forceEmit: true, - last: true, - }); - } - onPadKeyDown_(ev) { - if (isArrowKey(ev.key)) { - ev.preventDefault(); - } - const [dx, dy] = computeOffset(ev, [this.props.get('xKeyScale'), this.props.get('yKeyScale')], this.props.get('invertsY')); - if (dx === 0 && dy === 0) { - return; - } - this.value.setRawValue(new Point2d(this.value.rawValue.x + dx, this.value.rawValue.y + dy), { - forceEmit: false, - last: false, - }); - } - onPadKeyUp_(ev) { - const [dx, dy] = computeOffset(ev, [this.props.get('xKeyScale'), this.props.get('yKeyScale')], this.props.get('invertsY')); - if (dx === 0 && dy === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - class Point2dController { - constructor(doc, config) { - var _a, _b; - this.onPopupChildBlur_ = this.onPopupChildBlur_.bind(this); - this.onPopupChildKeydown_ = this.onPopupChildKeydown_.bind(this); - this.onPadButtonBlur_ = this.onPadButtonBlur_.bind(this); - this.onPadButtonClick_ = this.onPadButtonClick_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.foldable_ = Foldable.create(config.expanded); - this.popC_ = - config.pickerLayout === 'popup' - ? new PopupController(doc, { - viewProps: this.viewProps, - }) - : null; - const padC = new Point2dPickerController(doc, { - layout: config.pickerLayout, - props: new ValueMap({ - invertsY: createValue(config.invertsY), - max: createValue(config.max), - xKeyScale: config.axes[0].textProps.value('keyScale'), - yKeyScale: config.axes[1].textProps.value('keyScale'), - }), - value: this.value, - viewProps: this.viewProps, - }); - padC.view.allFocusableElements.forEach((elem) => { - elem.addEventListener('blur', this.onPopupChildBlur_); - elem.addEventListener('keydown', this.onPopupChildKeydown_); - }); - this.pickerC_ = padC; - this.textC_ = new PointNdTextController(doc, { - assembly: Point2dAssembly, - axes: config.axes, - parser: config.parser, - value: this.value, - viewProps: this.viewProps, - }); - this.view = new Point2dView(doc, { - expanded: this.foldable_.value('expanded'), - pickerLayout: config.pickerLayout, - viewProps: this.viewProps, - }); - this.view.textElement.appendChild(this.textC_.view.element); - (_a = this.view.buttonElement) === null || _a === void 0 ? void 0 : _a.addEventListener('blur', this.onPadButtonBlur_); - (_b = this.view.buttonElement) === null || _b === void 0 ? void 0 : _b.addEventListener('click', this.onPadButtonClick_); - if (this.popC_) { - this.view.element.appendChild(this.popC_.view.element); - this.popC_.view.element.appendChild(this.pickerC_.view.element); - connectValues({ - primary: this.foldable_.value('expanded'), - secondary: this.popC_.shows, - forward: (p) => p, - backward: (_, s) => s, - }); - } - else if (this.view.pickerElement) { - this.view.pickerElement.appendChild(this.pickerC_.view.element); - bindFoldable(this.foldable_, this.view.pickerElement); - } - } - get textController() { - return this.textC_; - } - onPadButtonBlur_(e) { - if (!this.popC_) { - return; - } - const elem = this.view.element; - const nextTarget = forceCast(e.relatedTarget); - if (!nextTarget || !elem.contains(nextTarget)) { - this.popC_.shows.rawValue = false; - } - } - onPadButtonClick_() { - this.foldable_.set('expanded', !this.foldable_.get('expanded')); - if (this.foldable_.get('expanded')) { - this.pickerC_.view.allFocusableElements[0].focus(); - } - } - onPopupChildBlur_(ev) { - if (!this.popC_) { - return; - } - const elem = this.popC_.view.element; - const nextTarget = findNextTarget(ev); - if (nextTarget && elem.contains(nextTarget)) { - return; - } - if (nextTarget && - nextTarget === this.view.buttonElement && - !supportsTouch(elem.ownerDocument)) { - return; - } - this.popC_.shows.rawValue = false; - } - onPopupChildKeydown_(ev) { - if (this.popC_) { - if (ev.key === 'Escape') { - this.popC_.shows.rawValue = false; - } - } - else if (this.view.pickerElement) { - if (ev.key === 'Escape') { - this.view.buttonElement.focus(); - } - } - } - } - - function point2dFromUnknown(value) { - return Point2d.isObject(value) - ? new Point2d(value.x, value.y) - : new Point2d(); - } - function writePoint2d(target, value) { - target.writeProperty('x', value.x); - target.writeProperty('y', value.y); - } - - function createConstraint$5(params, initialValue) { - return new PointNdConstraint({ - assembly: Point2dAssembly, - components: [ - createDimensionConstraint(Object.assign(Object.assign({}, params), params.x), initialValue.x), - createDimensionConstraint(Object.assign(Object.assign({}, params), params.y), initialValue.y), - ], - }); - } - function getSuitableMaxDimensionValue(params, rawValue) { - var _a, _b; - if (!isEmpty(params.min) || !isEmpty(params.max)) { - return Math.max(Math.abs((_a = params.min) !== null && _a !== void 0 ? _a : 0), Math.abs((_b = params.max) !== null && _b !== void 0 ? _b : 0)); - } - const step = getSuitableKeyScale(params); - return Math.max(Math.abs(step) * 10, Math.abs(rawValue) * 10); - } - function getSuitableMax(params, initialValue) { - var _a, _b; - const xr = getSuitableMaxDimensionValue(deepMerge(params, ((_a = params.x) !== null && _a !== void 0 ? _a : {})), initialValue.x); - const yr = getSuitableMaxDimensionValue(deepMerge(params, ((_b = params.y) !== null && _b !== void 0 ? _b : {})), initialValue.y); - return Math.max(xr, yr); - } - function shouldInvertY(params) { - if (!('y' in params)) { - return false; - } - const yParams = params.y; - if (!yParams) { - return false; - } - return 'inverted' in yParams ? !!yParams.inverted : false; - } - createPlugin({ - id: 'input-point2d', - type: 'input', - accept: (value, params) => { - if (!Point2d.isObject(value)) { - return null; - } - const result = parseRecord(params, (p) => (Object.assign(Object.assign({}, createPointDimensionParser(p)), { expanded: p.optional.boolean, picker: p.optional.custom(parsePickerLayout), readonly: p.optional.constant(false), x: p.optional.custom(parsePointDimensionParams), y: p.optional.object(Object.assign(Object.assign({}, createPointDimensionParser(p)), { inverted: p.optional.boolean })) }))); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: () => point2dFromUnknown, - constraint: (args) => createConstraint$5(args.params, args.initialValue), - equals: Point2d.equals, - writer: () => writePoint2d, - }, - controller: (args) => { - var _a, _b; - const doc = args.document; - const value = args.value; - const c = args.constraint; - const dParams = [args.params.x, args.params.y]; - return new Point2dController(doc, { - axes: value.rawValue.getComponents().map((comp, i) => { - var _a; - return createPointAxis({ - constraint: c.components[i], - initialValue: comp, - params: deepMerge(args.params, ((_a = dParams[i]) !== null && _a !== void 0 ? _a : {})), - }); - }), - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - invertsY: shouldInvertY(args.params), - max: getSuitableMax(args.params, value.rawValue), - parser: parseNumber, - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - value: value, - viewProps: args.viewProps, - }); - }, - }); - - class Point3d { - constructor(x = 0, y = 0, z = 0) { - this.x = x; - this.y = y; - this.z = z; - } - getComponents() { - return [this.x, this.y, this.z]; - } - static isObject(obj) { - if (isEmpty(obj)) { - return false; - } - const x = obj.x; - const y = obj.y; - const z = obj.z; - if (typeof x !== 'number' || - typeof y !== 'number' || - typeof z !== 'number') { - return false; - } - return true; - } - static equals(v1, v2) { - return v1.x === v2.x && v1.y === v2.y && v1.z === v2.z; - } - toObject() { - return { - x: this.x, - y: this.y, - z: this.z, - }; - } - } - const Point3dAssembly = { - toComponents: (p) => p.getComponents(), - fromComponents: (comps) => new Point3d(...comps), - }; - - function point3dFromUnknown(value) { - return Point3d.isObject(value) - ? new Point3d(value.x, value.y, value.z) - : new Point3d(); - } - function writePoint3d(target, value) { - target.writeProperty('x', value.x); - target.writeProperty('y', value.y); - target.writeProperty('z', value.z); - } - - function createConstraint$4(params, initialValue) { - return new PointNdConstraint({ - assembly: Point3dAssembly, - components: [ - createDimensionConstraint(Object.assign(Object.assign({}, params), params.x), initialValue.x), - createDimensionConstraint(Object.assign(Object.assign({}, params), params.y), initialValue.y), - createDimensionConstraint(Object.assign(Object.assign({}, params), params.z), initialValue.z), - ], - }); - } - createPlugin({ - id: 'input-point3d', - type: 'input', - accept: (value, params) => { - if (!Point3d.isObject(value)) { - return null; - } - const result = parseRecord(params, (p) => (Object.assign(Object.assign({}, createPointDimensionParser(p)), { readonly: p.optional.constant(false), x: p.optional.custom(parsePointDimensionParams), y: p.optional.custom(parsePointDimensionParams), z: p.optional.custom(parsePointDimensionParams) }))); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => point3dFromUnknown, - constraint: (args) => createConstraint$4(args.params, args.initialValue), - equals: Point3d.equals, - writer: (_args) => writePoint3d, - }, - controller: (args) => { - const value = args.value; - const c = args.constraint; - const dParams = [args.params.x, args.params.y, args.params.z]; - return new PointNdTextController(args.document, { - assembly: Point3dAssembly, - axes: value.rawValue.getComponents().map((comp, i) => { - var _a; - return createPointAxis({ - constraint: c.components[i], - initialValue: comp, - params: deepMerge(args.params, ((_a = dParams[i]) !== null && _a !== void 0 ? _a : {})), - }); - }), - parser: parseNumber, - value: value, - viewProps: args.viewProps, - }); - }, - }); - - class Point4d { - constructor(x = 0, y = 0, z = 0, w = 0) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - getComponents() { - return [this.x, this.y, this.z, this.w]; - } - static isObject(obj) { - if (isEmpty(obj)) { - return false; - } - const x = obj.x; - const y = obj.y; - const z = obj.z; - const w = obj.w; - if (typeof x !== 'number' || - typeof y !== 'number' || - typeof z !== 'number' || - typeof w !== 'number') { - return false; - } - return true; - } - static equals(v1, v2) { - return v1.x === v2.x && v1.y === v2.y && v1.z === v2.z && v1.w === v2.w; - } - toObject() { - return { - x: this.x, - y: this.y, - z: this.z, - w: this.w, - }; - } - } - const Point4dAssembly = { - toComponents: (p) => p.getComponents(), - fromComponents: (comps) => new Point4d(...comps), - }; - - function point4dFromUnknown(value) { - return Point4d.isObject(value) - ? new Point4d(value.x, value.y, value.z, value.w) - : new Point4d(); - } - function writePoint4d(target, value) { - target.writeProperty('x', value.x); - target.writeProperty('y', value.y); - target.writeProperty('z', value.z); - target.writeProperty('w', value.w); - } - - function createConstraint$3(params, initialValue) { - return new PointNdConstraint({ - assembly: Point4dAssembly, - components: [ - createDimensionConstraint(Object.assign(Object.assign({}, params), params.x), initialValue.x), - createDimensionConstraint(Object.assign(Object.assign({}, params), params.y), initialValue.y), - createDimensionConstraint(Object.assign(Object.assign({}, params), params.z), initialValue.z), - createDimensionConstraint(Object.assign(Object.assign({}, params), params.w), initialValue.w), - ], - }); - } - createPlugin({ - id: 'input-point4d', - type: 'input', - accept: (value, params) => { - if (!Point4d.isObject(value)) { - return null; - } - const result = parseRecord(params, (p) => (Object.assign(Object.assign({}, createPointDimensionParser(p)), { readonly: p.optional.constant(false), w: p.optional.custom(parsePointDimensionParams), x: p.optional.custom(parsePointDimensionParams), y: p.optional.custom(parsePointDimensionParams), z: p.optional.custom(parsePointDimensionParams) }))); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => point4dFromUnknown, - constraint: (args) => createConstraint$3(args.params, args.initialValue), - equals: Point4d.equals, - writer: (_args) => writePoint4d, - }, - controller: (args) => { - const value = args.value; - const c = args.constraint; - const dParams = [ - args.params.x, - args.params.y, - args.params.z, - args.params.w, - ]; - return new PointNdTextController(args.document, { - assembly: Point4dAssembly, - axes: value.rawValue.getComponents().map((comp, i) => { - var _a; - return createPointAxis({ - constraint: c.components[i], - initialValue: comp, - params: deepMerge(args.params, ((_a = dParams[i]) !== null && _a !== void 0 ? _a : {})), - }); - }), - parser: parseNumber, - value: value, - viewProps: args.viewProps, - }); - }, - }); - - function createConstraint$2(params) { - const constraints = []; - const lc = createListConstraint(params.options); - if (lc) { - constraints.push(lc); - } - return new CompositeConstraint(constraints); - } - createPlugin({ - id: 'input-string', - type: 'input', - accept: (value, params) => { - if (typeof value !== 'string') { - return null; - } - const result = parseRecord(params, (p) => ({ - readonly: p.optional.constant(false), - options: p.optional.custom(parseListOptions), - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => stringFromUnknown, - constraint: (args) => createConstraint$2(args.params), - writer: (_args) => writePrimitive, - }, - controller: (args) => { - const doc = args.document; - const value = args.value; - const c = args.constraint; - const lc = c && findConstraint(c, ListConstraint); - if (lc) { - return new ListController(doc, { - props: new ValueMap({ - options: lc.values.value('options'), - }), - value: value, - viewProps: args.viewProps, - }); - } - return new TextController(doc, { - parser: (v) => v, - props: ValueMap.fromObject({ - formatter: formatString, - }), - value: value, - viewProps: args.viewProps, - }); - }, - api(args) { - if (typeof args.controller.value.rawValue !== 'string') { - return null; - } - if (args.controller.valueController instanceof ListController) { - return new ListInputBindingApi(args.controller); - } - return null; - }, - }); - - const Constants = { - monitor: { - defaultInterval: 200, - defaultRows: 3, - }, - }; - - const cn$2 = ClassName('mll'); - class MultiLogView { - constructor(doc, config) { - this.onValueUpdate_ = this.onValueUpdate_.bind(this); - this.formatter_ = config.formatter; - this.element = doc.createElement('div'); - this.element.classList.add(cn$2()); - config.viewProps.bindClassModifiers(this.element); - const textareaElem = doc.createElement('textarea'); - textareaElem.classList.add(cn$2('i')); - textareaElem.style.height = `calc(var(${getCssVar('containerUnitSize')}) * ${config.rows})`; - textareaElem.readOnly = true; - config.viewProps.bindDisabled(textareaElem); - this.element.appendChild(textareaElem); - this.textareaElem_ = textareaElem; - config.value.emitter.on('change', this.onValueUpdate_); - this.value = config.value; - this.update_(); - } - update_() { - const elem = this.textareaElem_; - const shouldScroll = elem.scrollTop === elem.scrollHeight - elem.clientHeight; - const lines = []; - this.value.rawValue.forEach((value) => { - if (value !== undefined) { - lines.push(this.formatter_(value)); - } - }); - elem.textContent = lines.join('\n'); - if (shouldScroll) { - elem.scrollTop = elem.scrollHeight; - } - } - onValueUpdate_() { - this.update_(); - } - } - - class MultiLogController { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new MultiLogView(doc, { - formatter: config.formatter, - rows: config.rows, - value: this.value, - viewProps: this.viewProps, - }); - } - } - - const cn$1 = ClassName('sgl'); - class SingleLogView { - constructor(doc, config) { - this.onValueUpdate_ = this.onValueUpdate_.bind(this); - this.formatter_ = config.formatter; - this.element = doc.createElement('div'); - this.element.classList.add(cn$1()); - config.viewProps.bindClassModifiers(this.element); - const inputElem = doc.createElement('input'); - inputElem.classList.add(cn$1('i')); - inputElem.readOnly = true; - inputElem.type = 'text'; - config.viewProps.bindDisabled(inputElem); - this.element.appendChild(inputElem); - this.inputElement = inputElem; - config.value.emitter.on('change', this.onValueUpdate_); - this.value = config.value; - this.update_(); - } - update_() { - const values = this.value.rawValue; - const lastValue = values[values.length - 1]; - this.inputElement.value = - lastValue !== undefined ? this.formatter_(lastValue) : ''; - } - onValueUpdate_() { - this.update_(); - } - } - - class SingleLogController { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new SingleLogView(doc, { - formatter: config.formatter, - value: this.value, - viewProps: this.viewProps, - }); - } - } - - createPlugin({ - id: 'monitor-bool', - type: 'monitor', - accept: (value, params) => { - if (typeof value !== 'boolean') { - return null; - } - const result = parseRecord(params, (p) => ({ - readonly: p.required.constant(true), - rows: p.optional.number, - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => boolFromUnknown, - }, - controller: (args) => { - var _a; - if (args.value.rawValue.length === 1) { - return new SingleLogController(args.document, { - formatter: BooleanFormatter, - value: args.value, - viewProps: args.viewProps, - }); - } - return new MultiLogController(args.document, { - formatter: BooleanFormatter, - rows: (_a = args.params.rows) !== null && _a !== void 0 ? _a : Constants.monitor.defaultRows, - value: args.value, - viewProps: args.viewProps, - }); - }, - }); - - class GraphLogMonitorBindingApi extends BindingApi { - get max() { - return this.controller.valueController.props.get('max'); - } - set max(max) { - this.controller.valueController.props.set('max', max); - } - get min() { - return this.controller.valueController.props.get('min'); - } - set min(min) { - this.controller.valueController.props.set('min', min); - } - } - - const cn = ClassName('grl'); - class GraphLogView { - constructor(doc, config) { - this.onCursorChange_ = this.onCursorChange_.bind(this); - this.onValueUpdate_ = this.onValueUpdate_.bind(this); - this.element = doc.createElement('div'); - this.element.classList.add(cn()); - config.viewProps.bindClassModifiers(this.element); - this.formatter_ = config.formatter; - this.props_ = config.props; - this.cursor_ = config.cursor; - this.cursor_.emitter.on('change', this.onCursorChange_); - const svgElem = doc.createElementNS(SVG_NS, 'svg'); - svgElem.classList.add(cn('g')); - svgElem.style.height = `calc(var(${getCssVar('containerUnitSize')}) * ${config.rows})`; - this.element.appendChild(svgElem); - this.svgElem_ = svgElem; - const lineElem = doc.createElementNS(SVG_NS, 'polyline'); - this.svgElem_.appendChild(lineElem); - this.lineElem_ = lineElem; - const tooltipElem = doc.createElement('div'); - tooltipElem.classList.add(cn('t'), ClassName('tt')()); - this.element.appendChild(tooltipElem); - this.tooltipElem_ = tooltipElem; - config.value.emitter.on('change', this.onValueUpdate_); - this.value = config.value; - this.update_(); - } - get graphElement() { - return this.svgElem_; - } - update_() { - const bounds = this.svgElem_.getBoundingClientRect(); - const maxIndex = this.value.rawValue.length - 1; - const min = this.props_.get('min'); - const max = this.props_.get('max'); - const points = []; - this.value.rawValue.forEach((v, index) => { - if (v === undefined) { - return; - } - const x = mapRange(index, 0, maxIndex, 0, bounds.width); - const y = mapRange(v, min, max, bounds.height, 0); - points.push([x, y].join(',')); - }); - this.lineElem_.setAttributeNS(null, 'points', points.join(' ')); - const tooltipElem = this.tooltipElem_; - const value = this.value.rawValue[this.cursor_.rawValue]; - if (value === undefined) { - tooltipElem.classList.remove(cn('t', 'a')); - return; - } - const tx = mapRange(this.cursor_.rawValue, 0, maxIndex, 0, bounds.width); - const ty = mapRange(value, min, max, bounds.height, 0); - tooltipElem.style.left = `${tx}px`; - tooltipElem.style.top = `${ty}px`; - tooltipElem.textContent = `${this.formatter_(value)}`; - if (!tooltipElem.classList.contains(cn('t', 'a'))) { - tooltipElem.classList.add(cn('t', 'a'), cn('t', 'in')); - forceReflow(tooltipElem); - tooltipElem.classList.remove(cn('t', 'in')); - } - } - onValueUpdate_() { - this.update_(); - } - onCursorChange_() { - this.update_(); - } - } - - class GraphLogController { - constructor(doc, config) { - this.onGraphMouseMove_ = this.onGraphMouseMove_.bind(this); - this.onGraphMouseLeave_ = this.onGraphMouseLeave_.bind(this); - this.onGraphPointerDown_ = this.onGraphPointerDown_.bind(this); - this.onGraphPointerMove_ = this.onGraphPointerMove_.bind(this); - this.onGraphPointerUp_ = this.onGraphPointerUp_.bind(this); - this.props = config.props; - this.value = config.value; - this.viewProps = config.viewProps; - this.cursor_ = createValue(-1); - this.view = new GraphLogView(doc, { - cursor: this.cursor_, - formatter: config.formatter, - rows: config.rows, - props: this.props, - value: this.value, - viewProps: this.viewProps, - }); - if (!supportsTouch(doc)) { - this.view.element.addEventListener('mousemove', this.onGraphMouseMove_); - this.view.element.addEventListener('mouseleave', this.onGraphMouseLeave_); - } - else { - const ph = new PointerHandler(this.view.element); - ph.emitter.on('down', this.onGraphPointerDown_); - ph.emitter.on('move', this.onGraphPointerMove_); - ph.emitter.on('up', this.onGraphPointerUp_); - } - } - importProps(state) { - return importBladeState(state, null, (p) => ({ - max: p.required.number, - min: p.required.number, - }), (result) => { - this.props.set('max', result.max); - this.props.set('min', result.min); - return true; - }); - } - exportProps() { - return exportBladeState(null, { - max: this.props.get('max'), - min: this.props.get('min'), - }); - } - onGraphMouseLeave_() { - this.cursor_.rawValue = -1; - } - onGraphMouseMove_(ev) { - const bounds = this.view.element.getBoundingClientRect(); - this.cursor_.rawValue = Math.floor(mapRange(ev.offsetX, 0, bounds.width, 0, this.value.rawValue.length)); - } - onGraphPointerDown_(ev) { - this.onGraphPointerMove_(ev); - } - onGraphPointerMove_(ev) { - if (!ev.data.point) { - this.cursor_.rawValue = -1; - return; - } - this.cursor_.rawValue = Math.floor(mapRange(ev.data.point.x, 0, ev.data.bounds.width, 0, this.value.rawValue.length)); - } - onGraphPointerUp_() { - this.cursor_.rawValue = -1; - } - } - - function createFormatter(params) { - return !isEmpty(params.format) ? params.format : createNumberFormatter(2); - } - function createTextMonitor(args) { - var _a; - if (args.value.rawValue.length === 1) { - return new SingleLogController(args.document, { - formatter: createFormatter(args.params), - value: args.value, - viewProps: args.viewProps, - }); - } - return new MultiLogController(args.document, { - formatter: createFormatter(args.params), - rows: (_a = args.params.rows) !== null && _a !== void 0 ? _a : Constants.monitor.defaultRows, - value: args.value, - viewProps: args.viewProps, - }); - } - function createGraphMonitor(args) { - var _a, _b, _c; - return new GraphLogController(args.document, { - formatter: createFormatter(args.params), - rows: (_a = args.params.rows) !== null && _a !== void 0 ? _a : Constants.monitor.defaultRows, - props: ValueMap.fromObject({ - max: (_b = args.params.max) !== null && _b !== void 0 ? _b : 100, - min: (_c = args.params.min) !== null && _c !== void 0 ? _c : 0, - }), - value: args.value, - viewProps: args.viewProps, - }); - } - function shouldShowGraph(params) { - return params.view === 'graph'; - } - createPlugin({ - id: 'monitor-number', - type: 'monitor', - accept: (value, params) => { - if (typeof value !== 'number') { - return null; - } - const result = parseRecord(params, (p) => ({ - format: p.optional.function, - max: p.optional.number, - min: p.optional.number, - readonly: p.required.constant(true), - rows: p.optional.number, - view: p.optional.string, - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - defaultBufferSize: (params) => (shouldShowGraph(params) ? 64 : 1), - reader: (_args) => numberFromUnknown, - }, - controller: (args) => { - if (shouldShowGraph(args.params)) { - return createGraphMonitor(args); - } - return createTextMonitor(args); - }, - api: (args) => { - if (args.controller.valueController instanceof GraphLogController) { - return new GraphLogMonitorBindingApi(args.controller); - } - return null; - }, - }); - - createPlugin({ - id: 'monitor-string', - type: 'monitor', - accept: (value, params) => { - if (typeof value !== 'string') { - return null; - } - const result = parseRecord(params, (p) => ({ - multiline: p.optional.boolean, - readonly: p.required.constant(true), - rows: p.optional.number, - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: { - reader: (_args) => stringFromUnknown, - }, - controller: (args) => { - var _a; - const value = args.value; - const multiline = value.rawValue.length > 1 || args.params.multiline; - if (multiline) { - return new MultiLogController(args.document, { - formatter: formatString, - rows: (_a = args.params.rows) !== null && _a !== void 0 ? _a : Constants.monitor.defaultRows, - value: value, - viewProps: args.viewProps, - }); - } - return new SingleLogController(args.document, { - formatter: formatString, - value: value, - viewProps: args.viewProps, - }); - }, - }); - - class ButtonCellApi { - constructor(controller) { - this.controller_ = controller; - } - get disabled() { - return this.controller_.viewProps.get('disabled'); - } - set disabled(disabled) { - this.controller_.viewProps.set('disabled', disabled); - } - get title() { - var _a; - return (_a = this.controller_.props.get('title')) !== null && _a !== void 0 ? _a : ''; - } - set title(title) { - this.controller_.props.set('title', title); - } - on(eventName, handler) { - const bh = handler.bind(this); - const emitter = this.controller_.emitter; - emitter.on(eventName, () => { - bh(new TpEvent(this)); - }); - return this; - } - } - - class TpButtonGridEvent extends TpEvent { - constructor(target, cell, index) { - super(target); - this.cell = cell; - this.index = index; - } - } - - class ButtonGridApi extends BladeApi { - constructor(controller) { - super(controller); - this.cellToApiMap_ = new Map(); - this.emitter_ = new Emitter(); - const gc = this.controller.valueController; - gc.cellControllers.forEach((cc, i) => { - const api = new ButtonCellApi(cc); - this.cellToApiMap_.set(cc, api); - cc.emitter.on('click', () => { - const x = i % gc.size[0]; - const y = Math.floor(i / gc.size[0]); - this.emitter_.emit('click', { - event: new TpButtonGridEvent(this, api, [x, y]), - }); - }); - }); - } - cell(x, y) { - const gc = this.controller.valueController; - const cc = gc.cellControllers[y * gc.size[0] + x]; - return this.cellToApiMap_.get(cc); - } - on(eventName, handler) { - const bh = handler.bind(this); - this.emitter_.on(eventName, (ev) => { - bh(ev.event); - }); - return this; - } - } - - class ButtonGridController { - constructor(doc, config) { - this.size = config.size; - const [w, h] = this.size; - const bcs = []; - for (let y = 0; y < h; y++) { - for (let x = 0; x < w; x++) { - const bc = new ButtonController(doc, { - props: ValueMap.fromObject(Object.assign({}, config.cellConfig(x, y))), - viewProps: ViewProps.create(), - }); - bcs.push(bc); - } - } - this.cellCs_ = bcs; - this.viewProps = ViewProps.create(); - this.viewProps.handleDispose(() => { - this.cellCs_.forEach((c) => { - c.viewProps.set('disposed', true); - }); - }); - this.view = new PlainView(doc, { - viewProps: this.viewProps, - viewName: 'btngrid', - }); - this.view.element.style.gridTemplateColumns = `repeat(${w}, 1fr)`; - this.cellCs_.forEach((bc) => { - this.view.element.appendChild(bc.view.element); - }); - } - get cellControllers() { - return this.cellCs_; - } - } - - class ButtonGridBladeController extends BladeController { - constructor(doc, config) { - const bc = config.valueController; - const lc = new LabelController(doc, { - blade: config.blade, - props: config.labelProps, - valueController: bc, - }); - super({ - blade: config.blade, - view: lc.view, - viewProps: bc.viewProps, - }); - this.valueController = bc; - this.labelController = lc; - } - } - - const ButtonGridBladePlugin = createPlugin({ - id: 'buttongrid', - type: 'blade', - accept(params) { - const result = parseRecord(params, (p) => ({ - cells: p.required.function, - size: p.required.array(p.required.number), - view: p.required.constant('buttongrid'), - label: p.optional.string, - })); - return result ? { params: result } : null; - }, - controller(args) { - return new ButtonGridBladeController(args.document, { - blade: args.blade, - labelProps: ValueMap.fromObject({ - label: args.params.label, - }), - valueController: new ButtonGridController(args.document, { - cellConfig: args.params.cells, - size: args.params.size, - }), - }); - }, - api(args) { - if (args.controller instanceof ButtonGridBladeController) { - return new ButtonGridApi(args.controller); - } - return null; - }, - }); - - class CubicBezierApi extends BladeApi { - get label() { - return this.controller.labelController.props.get('label'); - } - set label(label) { - this.controller.labelController.props.set('label', label); - } - get value() { - return this.controller.valueController.value.rawValue; - } - set value(value) { - this.controller.valueController.value.rawValue = value; - } - on(eventName, handler) { - const bh = handler.bind(this); - this.controller.valueController.value.emitter.on(eventName, (ev) => { - bh(new TpChangeEvent(this, ev.rawValue, ev.options.last)); - }); - return this; - } - } - - function interpolate(x1, x2, t) { - return x1 * (1 - t) + x2 * t; - } - const MAX_ITERATION = 20; - const X_DELTA = 0.001; - const CACHE_RESOLUTION = 100; - function y(cb, x) { - let dt = 0.25; - let t = 0.5; - let y = -1; - for (let i = 0; i < MAX_ITERATION; i++) { - const [tx, ty] = cb.curve(t); - t += dt * (tx < x ? +1 : -1); - y = ty; - dt *= 0.5; - if (Math.abs(x - tx) < X_DELTA) { - break; - } - } - return y; - } - class CubicBezier { - constructor(x1 = 0, y1 = 0, x2 = 1, y2 = 1) { - this.cache_ = []; - this.comps_ = [x1, y1, x2, y2]; - } - get x1() { - return this.comps_[0]; - } - get y1() { - return this.comps_[1]; - } - get x2() { - return this.comps_[2]; - } - get y2() { - return this.comps_[3]; - } - static isObject(obj) { - if (isEmpty(obj)) { - return false; - } - if (!Array.isArray(obj)) { - return false; - } - return (typeof obj[0] === 'number' && - typeof obj[1] === 'number' && - typeof obj[2] === 'number' && - typeof obj[3] === 'number'); - } - static equals(v1, v2) { - return (v1.x1 === v2.x1 && v1.y1 === v2.y1 && v1.x2 === v2.x2 && v1.y2 === v2.y2); - } - curve(t) { - const x01 = interpolate(0, this.x1, t); - const y01 = interpolate(0, this.y1, t); - const x12 = interpolate(this.x1, this.x2, t); - const y12 = interpolate(this.y1, this.y2, t); - const x23 = interpolate(this.x2, 1, t); - const y23 = interpolate(this.y2, 1, t); - const xr0 = interpolate(x01, x12, t); - const yr0 = interpolate(y01, y12, t); - const xr1 = interpolate(x12, x23, t); - const yr1 = interpolate(y12, y23, t); - return [interpolate(xr0, xr1, t), interpolate(yr0, yr1, t)]; - } - y(x) { - if (this.cache_.length === 0) { - const cache = []; - for (let i = 0; i < CACHE_RESOLUTION; i++) { - cache.push(y(this, mapRange(i, 0, CACHE_RESOLUTION - 1, 0, 1))); - } - this.cache_ = cache; - } - return this.cache_[Math.round(mapRange(constrainRange(x, 0, 1), 0, 1, 0, CACHE_RESOLUTION - 1))]; - } - toObject() { - return [this.comps_[0], this.comps_[1], this.comps_[2], this.comps_[3]]; - } - } - const CubicBezierAssembly = { - toComponents: (p) => p.toObject(), - fromComponents: (comps) => new CubicBezier(...comps), - }; - - function cubicBezierToString(cb) { - const formatter = createNumberFormatter(2); - const comps = cb.toObject().map((c) => formatter(c)); - return `cubic-bezier(${comps.join(', ')})`; - } - const COMPS_EMPTY = [0, 0.5, 0.5, 1]; - function cubicBezierFromString(text) { - const m = text.match(/^cubic-bezier\s*\(\s*([0-9.]+)\s*,\s*([0-9.]+)\s*,\s*([0-9.]+)\s*,\s*([0-9.]+)\s*\)$/); - if (!m) { - return new CubicBezier(...COMPS_EMPTY); - } - const comps = [m[1], m[2], m[3], m[4]].reduce((comps, comp) => { - if (!comps) { - return null; - } - const n = Number(comp); - if (isNaN(n)) { - return null; - } - return [...comps, n]; - }, []); - return new CubicBezier(...(comps !== null && comps !== void 0 ? comps : COMPS_EMPTY)); - } - - const className$7 = ClassName('cbz'); - class CubicBezierView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(className$7()); - config.viewProps.bindClassModifiers(this.element); - config.foldable.bindExpandedClass(this.element, className$7(undefined, 'expanded')); - bindValueMap(config.foldable, 'completed', valueToClassName(this.element, className$7(undefined, 'cpl'))); - const headElem = doc.createElement('div'); - headElem.classList.add(className$7('h')); - this.element.appendChild(headElem); - const buttonElem = doc.createElement('button'); - buttonElem.classList.add(className$7('b')); - config.viewProps.bindDisabled(buttonElem); - const iconElem = doc.createElementNS(SVG_NS, 'svg'); - iconElem.innerHTML = ''; - buttonElem.appendChild(iconElem); - headElem.appendChild(buttonElem); - this.buttonElement = buttonElem; - const textElem = doc.createElement('div'); - textElem.classList.add(className$7('t')); - headElem.appendChild(textElem); - this.textElement = textElem; - if (config.pickerLayout === 'inline') { - const pickerElem = doc.createElement('div'); - pickerElem.classList.add(className$7('p')); - this.element.appendChild(pickerElem); - this.pickerElement = pickerElem; - } - else { - this.pickerElement = null; - } - } - } - - const className$6 = ClassName('cbzp'); - class CubicBezierPickerView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(className$6()); - config.viewProps.bindClassModifiers(this.element); - const graphElem = doc.createElement('div'); - graphElem.classList.add(className$6('g')); - this.element.appendChild(graphElem); - this.graphElement = graphElem; - const textElem = doc.createElement('div'); - textElem.classList.add(className$6('t')); - this.element.appendChild(textElem); - this.textElement = textElem; - } - } - - function waitToBeAddedToDom(elem, callback) { - const ob = new MutationObserver((ml) => { - for (const m of ml) { - if (m.type !== 'childList') { - continue; - } - m.addedNodes.forEach((elem) => { - if (!elem.contains(elem)) { - return; - } - callback(); - ob.disconnect(); - }); - } - }); - const doc = elem.ownerDocument; - ob.observe(doc.body, { - attributes: true, - childList: true, - subtree: true, - }); - } - - const className$5 = ClassName('cbzg'); - // TODO: Apply to core - function compose(h1, h2) { - return (input) => h2(h1(input)); - } - class CubicBezierGraphView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(className$5()); - config.viewProps.bindClassModifiers(this.element); - config.viewProps.bindTabIndex(this.element); - const previewElem = doc.createElement('div'); - previewElem.classList.add(className$5('p')); - this.element.appendChild(previewElem); - this.previewElement = previewElem; - const svgElem = doc.createElementNS(SVG_NS, 'svg'); - svgElem.classList.add(className$5('g')); - this.element.appendChild(svgElem); - this.svgElem_ = svgElem; - const guideElem = doc.createElementNS(SVG_NS, 'path'); - guideElem.classList.add(className$5('u')); - this.svgElem_.appendChild(guideElem); - this.guideElem_ = guideElem; - const lineElem = doc.createElementNS(SVG_NS, 'polyline'); - lineElem.classList.add(className$5('l')); - this.svgElem_.appendChild(lineElem); - this.lineElem_ = lineElem; - this.handleElems_ = [doc.createElement('div'), doc.createElement('div')]; - this.handleElems_.forEach((elem) => { - elem.classList.add(className$5('h')); - this.element.appendChild(elem); - }); - this.vectorElems_ = [ - doc.createElementNS(SVG_NS, 'line'), - doc.createElementNS(SVG_NS, 'line'), - ]; - this.vectorElems_.forEach((elem) => { - elem.classList.add(className$5('v')); - this.svgElem_.appendChild(elem); - }); - this.value_ = config.value; - this.value_.emitter.on('change', this.onValueChange_.bind(this)); - this.sel_ = config.selection; - this.handleElems_.forEach((elem, index) => { - bindValue(this.sel_, compose((selection) => selection === index, valueToClassName(elem, className$5('h', 'sel')))); - }); - waitToBeAddedToDom(this.element, () => { - this.refresh(); - }); - } - getVertMargin_(h) { - return h * 0.25; - } - valueToPosition(x, y) { - const { clientWidth: w, clientHeight: h } = this.element; - const vm = this.getVertMargin_(h); - return { - x: mapRange(x, 0, 1, 0, w), - y: mapRange(y, 0, 1, h - vm, vm), - }; - } - positionToValue(x, y) { - const bounds = this.element.getBoundingClientRect(); - const w = bounds.width; - const h = bounds.height; - const vm = this.getVertMargin_(h); - return { - x: constrainRange(mapRange(x, 0, w, 0, 1), 0, 1), - y: mapRange(y, h - vm, vm, 0, 1), - }; - } - refresh() { - this.guideElem_.setAttributeNS(null, 'd', [0, 1] - .map((index) => { - const p1 = this.valueToPosition(0, index); - const p2 = this.valueToPosition(1, index); - return [`M ${p1.x},${p1.y}`, `L ${p2.x},${p2.y}`].join(' '); - }) - .join(' ')); - const bezier = this.value_.rawValue; - const points = []; - let t = 0; - for (;;) { - const p = this.valueToPosition(...bezier.curve(t)); - points.push([p.x, p.y].join(',')); - if (t >= 1) { - break; - } - t = Math.min(t + 0.05, 1); - } - this.lineElem_.setAttributeNS(null, 'points', points.join(' ')); - const obj = bezier.toObject(); - [0, 1].forEach((index) => { - const p1 = this.valueToPosition(index, index); - const p2 = this.valueToPosition(obj[index * 2], obj[index * 2 + 1]); - const vElem = this.vectorElems_[index]; - vElem.setAttributeNS(null, 'x1', String(p1.x)); - vElem.setAttributeNS(null, 'y1', String(p1.y)); - vElem.setAttributeNS(null, 'x2', String(p2.x)); - vElem.setAttributeNS(null, 'y2', String(p2.y)); - const hElem = this.handleElems_[index]; - hElem.style.left = `${p2.x}px`; - hElem.style.top = `${p2.y}px`; - }); - } - onValueChange_() { - this.refresh(); - } - } - - const TICK_COUNT = 24; - const PREVIEW_DELAY = 400; - const PREVIEW_DURATION = 1000; - const className$4 = ClassName('cbzprv'); - class CubicBezierPreviewView { - constructor(doc, config) { - this.stopped_ = true; - this.startTime_ = -1; - this.onDispose_ = this.onDispose_.bind(this); - this.onTimer_ = this.onTimer_.bind(this); - this.onValueChange_ = this.onValueChange_.bind(this); - this.element = doc.createElement('div'); - this.element.classList.add(className$4()); - config.viewProps.bindClassModifiers(this.element); - const svgElem = doc.createElementNS(SVG_NS, 'svg'); - svgElem.classList.add(className$4('g')); - this.element.appendChild(svgElem); - this.svgElem_ = svgElem; - const ticksElem = doc.createElementNS(SVG_NS, 'path'); - ticksElem.classList.add(className$4('t')); - this.svgElem_.appendChild(ticksElem); - this.ticksElem_ = ticksElem; - const markerElem = doc.createElement('div'); - markerElem.classList.add(className$4('m')); - this.element.appendChild(markerElem); - this.markerElem_ = markerElem; - this.value_ = config.value; - this.value_.emitter.on('change', this.onValueChange_); - config.viewProps.handleDispose(this.onDispose_); - waitToBeAddedToDom(this.element, () => { - this.refresh(); - }); - } - play() { - this.stop(); - this.updateMarker_(0); - this.markerElem_.classList.add(className$4('m', 'a')); - this.startTime_ = new Date().getTime() + PREVIEW_DELAY; - this.stopped_ = false; - requestAnimationFrame(this.onTimer_); - } - stop() { - this.stopped_ = true; - this.markerElem_.classList.remove(className$4('m', 'a')); - } - onDispose_() { - this.stop(); - } - updateMarker_(progress) { - const p = this.value_.rawValue.y(constrainRange(progress, 0, 1)); - this.markerElem_.style.left = `${p * 100}%`; - } - refresh() { - const { clientWidth: w, clientHeight: h } = this.svgElem_; - const ds = []; - const bezier = this.value_.rawValue; - for (let i = 0; i < TICK_COUNT; i++) { - const px = mapRange(i, 0, TICK_COUNT - 1, 0, 1); - const x = mapRange(bezier.y(px), 0, 1, 0, w); - ds.push(`M ${x},0 v${h}`); - } - this.ticksElem_.setAttributeNS(null, 'd', ds.join(' ')); - } - onTimer_() { - if (this.startTime_ === null) { - return; - } - const dt = new Date().getTime() - this.startTime_; - const p = dt / PREVIEW_DURATION; - this.updateMarker_(p); - if (dt > PREVIEW_DURATION + PREVIEW_DELAY) { - this.stop(); - } - if (!this.stopped_) { - requestAnimationFrame(this.onTimer_); - } - } - onValueChange_() { - this.refresh(); - this.play(); - } - } - - function getDistance(x1, y1, x2, y2) { - const dx = x2 - x1; - const dy = y2 - y1; - return Math.sqrt(dx * dx + dy * dy); - } - function lockAngle(x1, y1, x2, y2) { - const d = getDistance(x1, y1, x2, y2); - const a = Math.atan2(y2 - y1, x2 - x1); - const la = (Math.round(a / (Math.PI / 4)) * Math.PI) / 4; - return { - x: x1 + Math.cos(la) * d, - y: y1 + Math.sin(la) * d, - }; - } - class CubicBezierGraphController { - constructor(doc, config) { - this.onKeyDown_ = this.onKeyDown_.bind(this); - this.onKeyUp_ = this.onKeyUp_.bind(this); - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.keyScale_ = config.keyScale; - this.value = config.value; - this.sel_ = createValue(0); - this.viewProps = config.viewProps; - this.view = new CubicBezierGraphView(doc, { - selection: this.sel_, - value: this.value, - viewProps: this.viewProps, - }); - this.view.element.addEventListener('keydown', this.onKeyDown_); - this.view.element.addEventListener('keyup', this.onKeyUp_); - this.prevView_ = new CubicBezierPreviewView(doc, { - value: this.value, - viewProps: this.viewProps, - }); - this.prevView_.element.addEventListener('mousedown', (ev) => { - ev.stopImmediatePropagation(); - ev.preventDefault(); - this.prevView_.play(); - }); - this.view.previewElement.appendChild(this.prevView_.element); - const ptHandler = new PointerHandler(this.view.element); - ptHandler.emitter.on('down', this.onPointerDown_); - ptHandler.emitter.on('move', this.onPointerMove_); - ptHandler.emitter.on('up', this.onPointerUp_); - } - refresh() { - this.view.refresh(); - this.prevView_.refresh(); - this.prevView_.play(); - } - updateValue_(point, locksAngle, opts) { - const index = this.sel_.rawValue; - const comps = this.value.rawValue.toObject(); - const vp = this.view.positionToValue(point.x, point.y); - const v = locksAngle ? lockAngle(index, index, vp.x, vp.y) : vp; - comps[index * 2] = v.x; - comps[index * 2 + 1] = v.y; - this.value.setRawValue(new CubicBezier(...comps), opts); - } - onPointerDown_(ev) { - const data = ev.data; - if (!data.point) { - return; - } - const bezier = this.value.rawValue; - const p1 = this.view.valueToPosition(bezier.x1, bezier.y1); - const d1 = getDistance(data.point.x, data.point.y, p1.x, p1.y); - const p2 = this.view.valueToPosition(bezier.x2, bezier.y2); - const d2 = getDistance(data.point.x, data.point.y, p2.x, p2.y); - this.sel_.rawValue = d1 <= d2 ? 0 : 1; - this.updateValue_(data.point, ev.shiftKey, { - forceEmit: false, - last: false, - }); - } - onPointerMove_(ev) { - const data = ev.data; - if (!data.point) { - return; - } - this.updateValue_(data.point, ev.shiftKey, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - const data = ev.data; - if (!data.point) { - return; - } - this.updateValue_(data.point, ev.shiftKey, { - forceEmit: true, - last: true, - }); - } - onKeyDown_(ev) { - if (isArrowKey(ev.key)) { - ev.preventDefault(); - } - const index = this.sel_.rawValue; - const comps = this.value.rawValue.toObject(); - const keyScale = this.keyScale_.rawValue; - comps[index * 2] += getStepForKey(keyScale, getHorizontalStepKeys(ev)); - comps[index * 2 + 1] += getStepForKey(keyScale, getVerticalStepKeys(ev)); - this.value.setRawValue(new CubicBezier(...comps), { - forceEmit: false, - last: false, - }); - } - onKeyUp_(ev) { - if (isArrowKey(ev.key)) { - ev.preventDefault(); - } - const keyScale = this.keyScale_.rawValue; - const xStep = getStepForKey(keyScale, getHorizontalStepKeys(ev)); - const yStep = getStepForKey(keyScale, getVerticalStepKeys(ev)); - if (xStep === 0 && yStep === 0) { - return; - } - this.value.setRawValue(this.value.rawValue, { - forceEmit: true, - last: true, - }); - } - } - - class CubicBezierPickerController { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.view = new CubicBezierPickerView(doc, { - viewProps: this.viewProps, - }); - this.gc_ = new CubicBezierGraphController(doc, { - keyScale: config.axis.textProps.value('keyScale'), - value: this.value, - viewProps: this.viewProps, - }); - this.view.graphElement.appendChild(this.gc_.view.element); - const xAxis = Object.assign(Object.assign({}, config.axis), { constraint: new RangeConstraint({ max: 1, min: 0 }) }); - const yAxis = Object.assign(Object.assign({}, config.axis), { constraint: undefined }); - this.tc_ = new PointNdTextController(doc, { - assembly: CubicBezierAssembly, - axes: [xAxis, yAxis, xAxis, yAxis], - parser: parseNumber, - value: this.value, - viewProps: this.viewProps, - }); - this.view.textElement.appendChild(this.tc_.view.element); - } - get allFocusableElements() { - return [ - this.gc_.view.element, - ...this.tc_.view.textViews.map((v) => v.inputElement), - ]; - } - refresh() { - this.gc_.refresh(); - } - } - - class CubicBezierController { - constructor(doc, config) { - this.onButtonBlur_ = this.onButtonBlur_.bind(this); - this.onButtonClick_ = this.onButtonClick_.bind(this); - this.onPopupChildBlur_ = this.onPopupChildBlur_.bind(this); - this.onPopupChildKeydown_ = this.onPopupChildKeydown_.bind(this); - this.value = config.value; - this.viewProps = config.viewProps; - this.foldable_ = Foldable.create(config.expanded); - this.view = new CubicBezierView(doc, { - foldable: this.foldable_, - pickerLayout: config.pickerLayout, - viewProps: this.viewProps, - }); - this.view.buttonElement.addEventListener('blur', this.onButtonBlur_); - this.view.buttonElement.addEventListener('click', this.onButtonClick_); - this.tc_ = new TextController(doc, { - parser: cubicBezierFromString, - props: ValueMap.fromObject({ - formatter: cubicBezierToString, - }), - value: this.value, - viewProps: this.viewProps, - }); - this.view.textElement.appendChild(this.tc_.view.element); - this.popC_ = - config.pickerLayout === 'popup' - ? new PopupController(doc, { - viewProps: this.viewProps, - }) - : null; - const pickerC = new CubicBezierPickerController(doc, { - axis: config.axis, - value: this.value, - viewProps: this.viewProps, - }); - pickerC.allFocusableElements.forEach((elem) => { - elem.addEventListener('blur', this.onPopupChildBlur_); - elem.addEventListener('keydown', this.onPopupChildKeydown_); - }); - this.pickerC_ = pickerC; - if (this.popC_) { - this.view.element.appendChild(this.popC_.view.element); - this.popC_.view.element.appendChild(this.pickerC_.view.element); - bindValue(this.popC_.shows, (shows) => { - if (shows) { - pickerC.refresh(); - } - }); - connectValues({ - primary: this.foldable_.value('expanded'), - secondary: this.popC_.shows, - forward: (p) => p, - backward: (_, s) => s, - }); - } - else if (this.view.pickerElement) { - this.view.pickerElement.appendChild(this.pickerC_.view.element); - bindFoldable(this.foldable_, this.view.pickerElement); - } - } - onButtonBlur_(ev) { - if (!this.popC_) { - return; - } - const nextTarget = forceCast(ev.relatedTarget); - if (!nextTarget || !this.popC_.view.element.contains(nextTarget)) { - this.popC_.shows.rawValue = false; - } - } - onButtonClick_() { - this.foldable_.set('expanded', !this.foldable_.get('expanded')); - if (this.foldable_.get('expanded')) { - this.pickerC_.allFocusableElements[0].focus(); - } - } - onPopupChildBlur_(ev) { - if (!this.popC_) { - return; - } - const elem = this.popC_.view.element; - const nextTarget = findNextTarget(ev); - if (nextTarget && elem.contains(nextTarget)) { - // Next target is in the popup - return; - } - if (nextTarget && - nextTarget === this.view.buttonElement && - !supportsTouch(elem.ownerDocument)) { - // Next target is the trigger button - return; - } - this.popC_.shows.rawValue = false; - } - onPopupChildKeydown_(ev) { - if (!this.popC_) { - return; - } - if (ev.key === 'Escape') { - this.popC_.shows.rawValue = false; - } - } - } - - function createConstraint$1() { - return new PointNdConstraint({ - assembly: CubicBezierAssembly, - components: [0, 1, 2, 3].map((index) => index % 2 === 0 - ? new RangeConstraint({ - min: 0, - max: 1, - }) - : undefined), - }); - } - const CubicBezierBladePlugin = createPlugin({ - id: 'cubicbezier', - type: 'blade', - accept(params) { - const result = parseRecord(params, (p) => ({ - value: p.required.array(p.required.number), - view: p.required.constant('cubicbezier'), - expanded: p.optional.boolean, - label: p.optional.string, - picker: p.optional.custom((v) => { - return v === 'inline' || v === 'popup' ? v : undefined; - }), - })); - return result ? { params: result } : null; - }, - controller(args) { - var _a, _b; - const rv = new CubicBezier(...args.params.value); - const v = createValue(rv, { - constraint: createConstraint$1(), - equals: CubicBezier.equals, - }); - const vc = new CubicBezierController(args.document, { - axis: { - textProps: ValueMap.fromObject({ - keyScale: 0.1, - pointerScale: 0.01, - formatter: createNumberFormatter(2), - }), - }, - expanded: (_a = args.params.expanded) !== null && _a !== void 0 ? _a : false, - pickerLayout: (_b = args.params.picker) !== null && _b !== void 0 ? _b : 'popup', - value: v, - viewProps: args.viewProps, - }); - return new LabeledValueBladeController(args.document, { - blade: args.blade, - props: ValueMap.fromObject({ - label: args.params.label, - }), - value: v, - valueController: vc, - }); - }, - api(args) { - if (!(args.controller instanceof LabeledValueBladeController)) { - return null; - } - if (!(args.controller.valueController instanceof CubicBezierController)) { - return null; - } - return new CubicBezierApi(args.controller); - }, - }); - - class FpsGraphBladeApi extends BladeApi { - get fps() { - return this.controller.valueController.fps; - } - get max() { - return this.controller.valueController.props.get('max'); - } - set max(max) { - this.controller.valueController.props.set('max', max); - } - get min() { - return this.controller.valueController.props.get('min'); - } - set min(min) { - this.controller.valueController.props.set('min', min); - } - begin() { - this.controller.valueController.begin(); - } - end() { - this.controller.valueController.end(); - } - on(eventName, handler) { - const bh = handler.bind(this); - const emitter = this.controller.valueController.ticker.emitter; - emitter.on(eventName, () => { - bh(new TpEvent(this)); - }); - return this; - } - } - - const MAX_TIMESTAMPS = 20; - class Fpswatch { - constructor() { - this.start_ = null; - this.duration_ = 0; - this.fps_ = null; - this.frameCount_ = 0; - this.timestamps_ = []; - } - get duration() { - return this.duration_; - } - get fps() { - return this.fps_; - } - begin(now) { - this.start_ = now.getTime(); - } - calculateFps_(nowTime) { - if (this.timestamps_.length === 0) { - return null; - } - const ts = this.timestamps_[0]; - return (1000 * (this.frameCount_ - ts.frameCount)) / (nowTime - ts.time); - } - compactTimestamps_() { - if (this.timestamps_.length <= MAX_TIMESTAMPS) { - return; - } - const len = this.timestamps_.length - MAX_TIMESTAMPS; - this.timestamps_.splice(0, len); - const df = this.timestamps_[0].frameCount; - this.timestamps_.forEach((ts) => { - ts.frameCount -= df; - }); - this.frameCount_ -= df; - } - end(now) { - if (this.start_ === null) { - return; - } - const t = now.getTime(); - this.duration_ = t - this.start_; - this.start_ = null; - this.fps_ = this.calculateFps_(t); - this.timestamps_.push({ - frameCount: this.frameCount_, - time: t, - }); - ++this.frameCount_; - this.compactTimestamps_(); - } - } - - const className$3 = ClassName('fps'); - class FpsView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(className$3()); - config.viewProps.bindClassModifiers(this.element); - this.graphElement = doc.createElement('div'); - this.graphElement.classList.add(className$3('g')); - this.element.appendChild(this.graphElement); - const labelElement = doc.createElement('div'); - labelElement.classList.add(className$3('l')); - this.element.appendChild(labelElement); - const valueElement = doc.createElement('span'); - valueElement.classList.add(className$3('v')); - valueElement.textContent = '--'; - labelElement.appendChild(valueElement); - this.valueElement = valueElement; - const unitElement = doc.createElement('span'); - unitElement.classList.add(className$3('u')); - unitElement.textContent = 'FPS'; - labelElement.appendChild(unitElement); - } - } - - class FpsGraphController { - constructor(doc, config) { - this.stopwatch_ = new Fpswatch(); - this.onTick_ = this.onTick_.bind(this); - this.ticker = config.ticker; - this.ticker.emitter.on('tick', this.onTick_); - this.props = config.props; - this.value_ = config.value; - this.viewProps = config.viewProps; - this.view = new FpsView(doc, { - viewProps: this.viewProps, - }); - this.graphC_ = new GraphLogController(doc, { - formatter: createNumberFormatter(0), - props: this.props, - rows: config.rows, - value: this.value_, - viewProps: this.viewProps, - }); - this.view.graphElement.appendChild(this.graphC_.view.element); - this.viewProps.handleDispose(() => { - this.graphC_.viewProps.set('disposed', true); - this.ticker.dispose(); - }); - } - get fps() { - return this.stopwatch_.fps; - } - begin() { - this.stopwatch_.begin(new Date()); - } - end() { - this.stopwatch_.end(new Date()); - } - onTick_() { - const fps = this.fps; - if (fps !== null) { - const buffer = this.value_.rawValue; - this.value_.rawValue = createPushedBuffer(buffer, fps); - this.view.valueElement.textContent = fps.toFixed(0); - } - } - } - - class FpsGraphBladeController extends BladeController { - constructor(doc, config) { - const fc = config.valueController; - const lc = new LabelController(doc, { - blade: config.blade, - props: config.labelProps, - valueController: fc, - }); - super({ - blade: config.blade, - view: lc.view, - viewProps: fc.viewProps, - }); - this.valueController = fc; - this.labelController = lc; - } - } - - function createTicker(document, interval) { - return interval === 0 - ? new ManualTicker() - : new IntervalTicker(document, interval !== null && interval !== void 0 ? interval : Constants.monitor.defaultInterval); - } - const FpsGraphBladePlugin = createPlugin({ - id: 'fpsgraph', - type: 'blade', - accept(params) { - const result = parseRecord(params, (p) => ({ - view: p.required.constant('fpsgraph'), - interval: p.optional.number, - label: p.optional.string, - rows: p.optional.number, - max: p.optional.number, - min: p.optional.number, - })); - return result ? { params: result } : null; - }, - controller(args) { - var _a, _b, _c, _d; - const interval = (_a = args.params.interval) !== null && _a !== void 0 ? _a : 500; - return new FpsGraphBladeController(args.document, { - blade: args.blade, - labelProps: ValueMap.fromObject({ - label: args.params.label, - }), - valueController: new FpsGraphController(args.document, { - props: ValueMap.fromObject({ - max: (_b = args.params.max) !== null && _b !== void 0 ? _b : 90, - min: (_c = args.params.min) !== null && _c !== void 0 ? _c : 0, - }), - rows: (_d = args.params.rows) !== null && _d !== void 0 ? _d : 2, - ticker: createTicker(args.document, interval), - value: createValue(initializeBuffer(80)), - viewProps: args.viewProps, - }), - }); - }, - api(args) { - if (!(args.controller instanceof FpsGraphBladeController)) { - return null; - } - return new FpsGraphBladeApi(args.controller); - }, - }); - - class Interval { - constructor(min, max) { - this.min = min; - this.max = max; - } - static isObject(obj) { - if (typeof obj !== 'object' || obj === null) { - return false; - } - const min = obj.min; - const max = obj.max; - if (typeof min !== 'number' || typeof max !== 'number') { - return false; - } - return true; - } - static equals(v1, v2) { - return v1.min === v2.min && v1.max === v2.max; - } - get length() { - return this.max - this.min; - } - toObject() { - return { - min: this.min, - max: this.max, - }; - } - } - const IntervalAssembly = { - fromComponents: (comps) => new Interval(comps[0], comps[1]), - toComponents: (p) => [p.min, p.max], - }; - - class IntervalConstraint { - constructor(edge) { - this.edge = edge; - } - constrain(value) { - var _a, _b, _c, _d, _e, _f, _g, _h; - if (value.min <= value.max) { - return new Interval((_b = (_a = this.edge) === null || _a === void 0 ? void 0 : _a.constrain(value.min)) !== null && _b !== void 0 ? _b : value.min, (_d = (_c = this.edge) === null || _c === void 0 ? void 0 : _c.constrain(value.max)) !== null && _d !== void 0 ? _d : value.max); - } - const c = (value.min + value.max) / 2; - return new Interval((_f = (_e = this.edge) === null || _e === void 0 ? void 0 : _e.constrain(c)) !== null && _f !== void 0 ? _f : c, (_h = (_g = this.edge) === null || _g === void 0 ? void 0 : _g.constrain(c)) !== null && _h !== void 0 ? _h : c); - } - } - - const className$2 = ClassName('rsltxt'); - class RangeSliderTextView { - constructor(doc, config) { - this.sliderView_ = config.sliderView; - this.textView_ = config.textView; - this.element = doc.createElement('div'); - this.element.classList.add(className$2()); - const sliderElem = doc.createElement('div'); - sliderElem.classList.add(className$2('s')); - sliderElem.appendChild(this.sliderView_.element); - this.element.appendChild(sliderElem); - const textElem = doc.createElement('div'); - textElem.classList.add(className$2('t')); - textElem.appendChild(this.textView_.element); - this.element.appendChild(textElem); - } - } - - const className$1 = ClassName('rsl'); - class RangeSliderView { - constructor(doc, config) { - this.onSliderPropsChange_ = this.onSliderPropsChange_.bind(this); - this.onValueChange_ = this.onValueChange_.bind(this); - this.sliderProps_ = config.sliderProps; - this.sliderProps_.emitter.on('change', this.onSliderPropsChange_); - this.element = doc.createElement('div'); - this.element.classList.add(className$1()); - config.viewProps.bindClassModifiers(this.element); - this.value_ = config.value; - this.value_.emitter.on('change', this.onValueChange_); - const trackElem = doc.createElement('div'); - trackElem.classList.add(className$1('t')); - this.element.appendChild(trackElem); - this.trackElement = trackElem; - const barElem = doc.createElement('div'); - barElem.classList.add(className$1('b')); - trackElem.appendChild(barElem); - this.barElement = barElem; - const knobElems = ['min', 'max'].map((modifier) => { - const elem = doc.createElement('div'); - elem.classList.add(className$1('k'), className$1('k', modifier)); - trackElem.appendChild(elem); - return elem; - }); - this.knobElements = [knobElems[0], knobElems[1]]; - this.update_(); - } - valueToX_(value) { - const min = this.sliderProps_.get('min'); - const max = this.sliderProps_.get('max'); - return constrainRange(mapRange(value, min, max, 0, 1), 0, 1) * 100; - } - update_() { - const v = this.value_.rawValue; - if (v.length === 0) { - this.element.classList.add(className$1(undefined, 'zero')); - } - else { - this.element.classList.remove(className$1(undefined, 'zero')); - } - const xs = [this.valueToX_(v.min), this.valueToX_(v.max)]; - this.barElement.style.left = `${xs[0]}%`; - this.barElement.style.right = `${100 - xs[1]}%`; - this.knobElements.forEach((elem, index) => { - elem.style.left = `${xs[index]}%`; - }); - } - onSliderPropsChange_() { - this.update_(); - } - onValueChange_() { - this.update_(); - } - } - - class RangeSliderController { - constructor(doc, config) { - this.grabbing_ = null; - this.grabOffset_ = 0; - this.onPointerDown_ = this.onPointerDown_.bind(this); - this.onPointerMove_ = this.onPointerMove_.bind(this); - this.onPointerUp_ = this.onPointerUp_.bind(this); - this.sliderProps = config.sliderProps; - this.viewProps = config.viewProps; - this.value = config.value; - this.view = new RangeSliderView(doc, { - sliderProps: this.sliderProps, - value: this.value, - viewProps: config.viewProps, - }); - const ptHandler = new PointerHandler(this.view.trackElement); - ptHandler.emitter.on('down', this.onPointerDown_); - ptHandler.emitter.on('move', this.onPointerMove_); - ptHandler.emitter.on('up', this.onPointerUp_); - } - ofs_() { - if (this.grabbing_ === 'min') { - return this.view.knobElements[0].getBoundingClientRect().width / 2; - } - if (this.grabbing_ === 'max') { - return -this.view.knobElements[1].getBoundingClientRect().width / 2; - } - return 0; - } - valueFromData_(data) { - if (!data.point) { - return null; - } - const p = (data.point.x + this.ofs_()) / data.bounds.width; - const min = this.sliderProps.get('min'); - const max = this.sliderProps.get('max'); - return mapRange(p, 0, 1, min, max); - } - onPointerDown_(ev) { - if (!ev.data.point) { - return; - } - const p = ev.data.point.x / ev.data.bounds.width; - const v = this.value.rawValue; - const min = this.sliderProps.get('min'); - const max = this.sliderProps.get('max'); - const pmin = mapRange(v.min, min, max, 0, 1); - const pmax = mapRange(v.max, min, max, 0, 1); - if (Math.abs(pmax - p) <= 0.025) { - this.grabbing_ = 'max'; - } - else if (Math.abs(pmin - p) <= 0.025) { - this.grabbing_ = 'min'; - } - else if (p >= pmin && p <= pmax) { - this.grabbing_ = 'length'; - this.grabOffset_ = mapRange(p - pmin, 0, 1, 0, max - min); - } - else if (p < pmin) { - this.grabbing_ = 'min'; - this.onPointerMove_(ev); - } - else if (p > pmax) { - this.grabbing_ = 'max'; - this.onPointerMove_(ev); - } - } - applyPointToValue_(data, opts) { - const v = this.valueFromData_(data); - if (v === null) { - return; - } - const rmin = this.sliderProps.get('min'); - const rmax = this.sliderProps.get('max'); - if (this.grabbing_ === 'min') { - this.value.setRawValue(new Interval(v, this.value.rawValue.max), opts); - } - else if (this.grabbing_ === 'max') { - this.value.setRawValue(new Interval(this.value.rawValue.min, v), opts); - } - else if (this.grabbing_ === 'length') { - const len = this.value.rawValue.length; - let min = v - this.grabOffset_; - let max = min + len; - if (min < rmin) { - min = rmin; - max = rmin + len; - } - else if (max > rmax) { - min = rmax - len; - max = rmax; - } - this.value.setRawValue(new Interval(min, max), opts); - } - } - onPointerMove_(ev) { - this.applyPointToValue_(ev.data, { - forceEmit: false, - last: false, - }); - } - onPointerUp_(ev) { - this.applyPointToValue_(ev.data, { - forceEmit: true, - last: true, - }); - this.grabbing_ = null; - } - } - - class RangeSliderTextController { - constructor(doc, config) { - this.value = config.value; - this.viewProps = config.viewProps; - this.sc_ = new RangeSliderController(doc, config); - const axis = { - constraint: config.constraint, - textProps: config.textProps, - }; - this.tc_ = new PointNdTextController(doc, { - assembly: IntervalAssembly, - axes: [axis, axis], - parser: config.parser, - value: this.value, - viewProps: config.viewProps, - }); - this.view = new RangeSliderTextView(doc, { - sliderView: this.sc_.view, - textView: this.tc_.view, - }); - } - get textController() { - return this.tc_; - } - } - - function intervalFromUnknown(value) { - return Interval.isObject(value) - ? new Interval(value.min, value.max) - : new Interval(0, 0); - } - function writeInterval(target, value) { - target.writeProperty('max', value.max); - target.writeProperty('min', value.min); - } - - function createConstraint(params) { - const constraints = []; - const rc = createRangeConstraint(params); - if (rc) { - constraints.push(rc); - } - const sc = createStepConstraint(params); - if (sc) { - constraints.push(sc); - } - return new IntervalConstraint(new CompositeConstraint(constraints)); - } - const IntervalInputPlugin = createPlugin({ - id: 'input-interval', - type: 'input', - accept: (exValue, params) => { - if (!Interval.isObject(exValue)) { - return null; - } - const result = parseRecord(params, (p) => (Object.assign(Object.assign({}, createNumberTextInputParamsParser(p)), { readonly: p.optional.constant(false) }))); - return result - ? { - initialValue: new Interval(exValue.min, exValue.max), - params: result, - } - : null; - }, - binding: { - reader: (_args) => intervalFromUnknown, - constraint: (args) => createConstraint(args.params), - equals: Interval.equals, - writer: (_args) => writeInterval, - }, - controller(args) { - const v = args.value; - const c = args.constraint; - if (!(c instanceof IntervalConstraint)) { - throw TpError.shouldNeverHappen(); - } - const midValue = (v.rawValue.min + v.rawValue.max) / 2; - const textProps = ValueMap.fromObject(createNumberTextPropsObject(args.params, midValue)); - const drc = c.edge && findConstraint(c.edge, DefiniteRangeConstraint); - if (drc) { - return new RangeSliderTextController(args.document, { - constraint: c.edge, - parser: parseNumber, - sliderProps: new ValueMap({ - keyScale: textProps.value('keyScale'), - max: drc.values.value('max'), - min: drc.values.value('min'), - }), - textProps: textProps, - value: v, - viewProps: args.viewProps, - }); - } - const axis = { - constraint: c.edge, - textProps: textProps, - }; - return new PointNdTextController(args.document, { - assembly: IntervalAssembly, - axes: [axis, axis], - parser: parseNumber, - value: v, - viewProps: args.viewProps, - }); - }, - }); - - class RadioCellApi { - constructor(controller) { - this.controller_ = controller; - } - get disabled() { - return this.controller_.viewProps.get('disabled'); - } - set disabled(disabled) { - this.controller_.viewProps.set('disabled', disabled); - } - get title() { - var _a; - return (_a = this.controller_.props.get('title')) !== null && _a !== void 0 ? _a : ''; - } - set title(title) { - this.controller_.props.set('title', title); - } - } - - class TpRadioGridChangeEvent extends TpChangeEvent { - constructor(target, cell, index, value, last) { - super(target, value, last); - this.cell = cell; - this.index = index; - } - } - - class RadioGridApi extends BladeApi { - constructor(controller) { - super(controller); - this.cellToApiMap_ = new Map(); - const gc = this.controller.valueController; - gc.cellControllers.forEach((cc) => { - const api = new RadioCellApi(cc); - this.cellToApiMap_.set(cc, api); - }); - } - get value() { - return this.controller.value; - } - cell(x, y) { - const gc = this.controller.valueController; - const cc = gc.cellControllers[y * gc.size[0] + x]; - return this.cellToApiMap_.get(cc); - } - on(eventName, handler) { - const bh = handler.bind(this); - this.controller.value.emitter.on(eventName, (ev) => { - const gc = this.controller.valueController; - const cc = gc.findCellByValue(ev.rawValue); - if (!cc) { - return; - } - const capi = this.cellToApiMap_.get(cc); - if (!capi) { - return; - } - const i = gc.cellControllers.indexOf(cc); - bh(new TpRadioGridChangeEvent(this, capi, [i % gc.size[0], Math.floor(i / gc.size[0])], ev.rawValue)); - }); - } - } - - const className = ClassName('rad'); - class RadioView { - constructor(doc, config) { - this.element = doc.createElement('div'); - this.element.classList.add(className()); - config.viewProps.bindClassModifiers(this.element); - const labelElem = doc.createElement('label'); - labelElem.classList.add(className('l')); - this.element.appendChild(labelElem); - const inputElem = doc.createElement('input'); - inputElem.classList.add(className('i')); - inputElem.name = config.name; - inputElem.type = 'radio'; - config.viewProps.bindDisabled(inputElem); - labelElem.appendChild(inputElem); - this.inputElement = inputElem; - const bodyElem = doc.createElement('div'); - bodyElem.classList.add(className('b')); - labelElem.appendChild(bodyElem); - const titleElem = doc.createElement('div'); - titleElem.classList.add(className('t')); - bodyElem.appendChild(titleElem); - bindValueMap(config.props, 'title', (title) => { - titleElem.textContent = title; - }); - } - } - - class RadioController { - constructor(doc, config) { - this.props = config.props; - this.viewProps = config.viewProps; - this.view = new RadioView(doc, { - name: config.name, - props: this.props, - viewProps: this.viewProps, - }); - } - } - - class RadioGridController { - constructor(doc, config) { - this.cellCs_ = []; - this.cellValues_ = []; - this.onCellInputChange_ = this.onCellInputChange_.bind(this); - this.size = config.size; - const [w, h] = this.size; - for (let y = 0; y < h; y++) { - for (let x = 0; x < w; x++) { - const bc = new RadioController(doc, { - name: config.groupName, - props: ValueMap.fromObject(Object.assign({}, config.cellConfig(x, y))), - viewProps: ViewProps.create(), - }); - this.cellCs_.push(bc); - this.cellValues_.push(config.cellConfig(x, y).value); - } - } - this.value = config.value; - bindValue(this.value, (value) => { - const cc = this.findCellByValue(value); - if (!cc) { - return; - } - cc.view.inputElement.checked = true; - }); - this.viewProps = ViewProps.create(); - this.view = new PlainView(doc, { - viewProps: this.viewProps, - viewName: 'radgrid', - }); - this.view.element.style.gridTemplateColumns = `repeat(${w}, 1fr)`; - this.cellCs_.forEach((bc) => { - bc.view.inputElement.addEventListener('change', this.onCellInputChange_); - this.view.element.appendChild(bc.view.element); - }); - } - get cellControllers() { - return this.cellCs_; - } - findCellByValue(value) { - const index = this.cellValues_.findIndex((v) => v === value); - if (index < 0) { - return null; - } - return this.cellCs_[index]; - } - onCellInputChange_(ev) { - const inputElem = ev.currentTarget; - const index = this.cellCs_.findIndex((c) => c.view.inputElement === inputElem); - if (index < 0) { - return; - } - this.value.rawValue = this.cellValues_[index]; - } - } - - const RadioGridBladePlugin = (function () { - return createPlugin({ - id: 'radiogrid', - type: 'blade', - accept(params) { - const result = parseRecord(params, (p) => ({ - cells: p.required.function, - groupName: p.required.string, - size: p.required.array(p.required.number), - value: p.required.raw, - view: p.required.constant('radiogrid'), - label: p.optional.string, - })); - return result ? { params: result } : null; - }, - controller(args) { - const value = createValue(args.params.value); - return new LabeledValueBladeController(args.document, { - blade: args.blade, - props: ValueMap.fromObject({ - label: args.params.label, - }), - value: value, - valueController: new RadioGridController(args.document, { - groupName: args.params.groupName, - cellConfig: args.params.cells, - size: args.params.size, - value: value, - }), - }); - }, - api(args) { - if (!(args.controller instanceof LabeledValueBladeController)) { - return null; - } - if (!(args.controller.valueController instanceof RadioGridController)) { - return null; - } - return new RadioGridApi(args.controller); - }, - }); - })(); - - function createRadioGridInputPlugin(config) { - return createPlugin({ - id: 'input-radiogrid', - type: 'input', - accept(value, params) { - if (!config.isType(value)) { - return null; - } - const result = parseRecord(params, (p) => ({ - cells: p.required.function, - groupName: p.required.string, - size: p.required.array(p.required.number), - view: p.required.constant('radiogrid'), - })); - return result - ? { - initialValue: value, - params: result, - } - : null; - }, - binding: config.binding, - controller: (args) => { - return new RadioGridController(args.document, { - cellConfig: args.params.cells, - groupName: args.params.groupName, - size: args.params.size, - value: args.value, - }); - }, - }); - } - const RadioGruidNumberInputPlugin = createRadioGridInputPlugin({ - isType: (value) => { - return typeof value === 'number'; - }, - binding: { - reader: (_args) => numberFromUnknown, - writer: (_args) => writePrimitive, - }, - }); - const RadioGruidStringInputPlugin = createRadioGridInputPlugin({ - isType: (value) => { - return typeof value === 'string'; - }, - binding: { - reader: (_args) => stringFromUnknown, - writer: (_args) => writePrimitive, - }, - }); - const RadioGruidBooleanInputPlugin = createRadioGridInputPlugin({ - isType: (value) => { - return typeof value === 'boolean'; - }, - binding: { - reader: (_args) => boolFromUnknown, - writer: (_args) => writePrimitive, - }, - }); - - const id = 'essentials'; - const css = '.tp-cbzgv,.tp-radv_b,.tp-rslv_k,.tp-cbzv_b{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:rgba(0,0,0,0);border-width:0;font-family:inherit;font-size:inherit;font-weight:inherit;margin:0;outline:none;padding:0}.tp-radv_b,.tp-rslv_k,.tp-cbzv_b{background-color:var(--btn-bg);border-radius:var(--bld-br);color:var(--btn-fg);cursor:pointer;display:block;font-weight:bold;height:var(--cnt-usz);line-height:var(--cnt-usz);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tp-radv_b:hover,.tp-rslv_k:hover,.tp-cbzv_b:hover{background-color:var(--btn-bg-h)}.tp-radv_b:focus,.tp-rslv_k:focus,.tp-cbzv_b:focus{background-color:var(--btn-bg-f)}.tp-radv_b:active,.tp-rslv_k:active,.tp-cbzv_b:active{background-color:var(--btn-bg-a)}.tp-radv_b:disabled,.tp-rslv_k:disabled,.tp-cbzv_b:disabled{opacity:.5}.tp-cbzgv{background-color:var(--in-bg);border-radius:var(--bld-br);box-sizing:border-box;color:var(--in-fg);font-family:inherit;height:var(--cnt-usz);line-height:var(--cnt-usz);min-width:0;width:100%}.tp-cbzgv:hover{background-color:var(--in-bg-h)}.tp-cbzgv:focus{background-color:var(--in-bg-f)}.tp-cbzgv:active{background-color:var(--in-bg-a)}.tp-cbzgv:disabled{opacity:.5}.tp-btngridv{border-radius:var(--bld-br);display:grid;overflow:hidden;gap:2px}.tp-btngridv.tp-v-disabled{opacity:.5}.tp-btngridv .tp-btnv_b:disabled{opacity:1}.tp-btngridv .tp-btnv_b:disabled .tp-btnv_t{opacity:.5}.tp-btngridv .tp-btnv_b{border-radius:0}.tp-cbzv{position:relative}.tp-cbzv_h{display:flex}.tp-cbzv_b{margin-right:4px;position:relative;width:var(--cnt-usz)}.tp-cbzv_b svg{display:block;height:16px;left:50%;margin-left:-8px;margin-top:-8px;position:absolute;top:50%;width:16px}.tp-cbzv_b svg path{stroke:var(--bs-bg);stroke-width:2}.tp-cbzv_t{flex:1}.tp-cbzv_p{height:0;margin-top:0;opacity:0;overflow:hidden;transition:height .2s ease-in-out,opacity .2s linear,margin .2s ease-in-out}.tp-cbzv.tp-cbzv-expanded .tp-cbzv_p{margin-top:var(--cnt-usp);opacity:1}.tp-cbzv.tp-cbzv-cpl .tp-cbzv_p{overflow:visible}.tp-cbzv .tp-popv{left:calc(-1 * var(--cnt-hp));position:absolute;right:calc(-1 * var(--cnt-hp));top:var(--cnt-usz)}.tp-cbzpv_t{margin-top:var(--cnt-usp)}.tp-cbzgv{height:auto;overflow:hidden;position:relative}.tp-cbzgv.tp-v-disabled{opacity:.5}.tp-cbzgv_p{left:16px;position:absolute;right:16px;top:0}.tp-cbzgv_g{cursor:pointer;display:block;height:calc(var(--cnt-usz) * 5);width:100%}.tp-cbzgv_u{opacity:.1;stroke:var(--in-fg);stroke-dasharray:1}.tp-cbzgv_l{fill:rgba(0,0,0,0);stroke:var(--in-fg)}.tp-cbzgv_v{opacity:.5;stroke:var(--in-fg);stroke-dasharray:1}.tp-cbzgv_h{border:var(--in-fg) solid 1px;border-radius:50%;box-sizing:border-box;height:4px;margin-left:-2px;margin-top:-2px;pointer-events:none;position:absolute;width:4px}.tp-cbzgv:focus .tp-cbzgv_h-sel{background-color:var(--in-fg);border-width:0}.tp-cbzprvv{cursor:pointer;height:4px;padding:4px 0;position:relative}.tp-cbzprvv_g{display:block;height:100%;overflow:visible;width:100%}.tp-cbzprvv_t{opacity:.5;stroke:var(--mo-fg)}.tp-cbzprvv_m{background-color:var(--mo-fg);border-radius:50%;height:4px;margin-left:-2px;margin-top:-2px;opacity:0;position:absolute;top:50%;transition:opacity .2s ease-out;width:4px}.tp-cbzprvv_m.tp-cbzprvv_m-a{opacity:1}.tp-fpsv{position:relative}.tp-fpsv_l{bottom:4px;color:var(--mo-fg);line-height:1;right:4px;pointer-events:none;position:absolute}.tp-fpsv_u{margin-left:.2em;opacity:.7}.tp-rslv{cursor:pointer;padding-left:8px;padding-right:8px}.tp-rslv.tp-v-disabled{opacity:.5}.tp-rslv_t{height:calc(var(--cnt-usz));position:relative}.tp-rslv_t::before{background-color:var(--in-bg);border-radius:1px;content:"";height:2px;margin-top:-1px;position:absolute;top:50%;left:-4px;right:-4px}.tp-rslv_b{bottom:0;top:0;position:absolute}.tp-rslv_b::before{background-color:var(--in-fg);content:"";height:2px;margin-top:-1px;position:absolute;top:50%;left:0;right:0}.tp-rslv_k{height:calc(var(--cnt-usz) - 8px);margin-top:calc((var(--cnt-usz) - 8px)/-2);position:absolute;top:50%;width:8px}.tp-rslv_k.tp-rslv_k-min{margin-left:-8px}.tp-rslv_k.tp-rslv_k-max{margin-left:0}.tp-rslv.tp-rslv-zero .tp-rslv_k.tp-rslv_k-min{border-bottom-right-radius:0;border-top-right-radius:0}.tp-rslv.tp-rslv-zero .tp-rslv_k.tp-rslv_k-max{border-bottom-left-radius:0;border-top-left-radius:0}.tp-rsltxtv{display:flex}.tp-rsltxtv_s{flex:1}.tp-rsltxtv_t{flex:1;margin-left:4px}.tp-radv_l{display:block;position:relative}.tp-radv_i{left:0;opacity:0;position:absolute;top:0}.tp-radv_b{opacity:.5}.tp-radv_i:hover+.tp-radv_b{background-color:var(--btn-bg-h)}.tp-radv_i:focus+.tp-radv_b{background-color:var(--btn-bg-f)}.tp-radv_i:active+.tp-radv_b{background-color:var(--btn-bg-a)}.tp-radv_i:checked+.tp-radv_b{opacity:1}.tp-radv_t{bottom:0;color:inherit;left:0;overflow:hidden;position:absolute;right:0;text-align:center;text-overflow:ellipsis;top:0}.tp-radv_i:disabled+.tp-radv_b>.tp-radv_t{opacity:.5}.tp-radgridv{border-radius:var(--bld-br);display:grid;overflow:hidden;gap:2px}.tp-radgridv.tp-v-disabled{opacity:.5}.tp-radgridv .tp-radv_b{border-radius:0}'; - const plugins = [ - ButtonGridBladePlugin, - CubicBezierBladePlugin, - FpsGraphBladePlugin, - IntervalInputPlugin, - RadioGridBladePlugin, - RadioGruidBooleanInputPlugin, - RadioGruidNumberInputPlugin, - RadioGruidStringInputPlugin, - ]; - - var EssentialsPlugin = /*#__PURE__*/Object.freeze({ - __proto__: null, - ButtonCellApi: ButtonCellApi, - ButtonGridApi: ButtonGridApi, - ButtonGridController: ButtonGridController, - CubicBezier: CubicBezier, - CubicBezierApi: CubicBezierApi, - CubicBezierAssembly: CubicBezierAssembly, - CubicBezierController: CubicBezierController, - CubicBezierGraphController: CubicBezierGraphController, - CubicBezierGraphView: CubicBezierGraphView, - CubicBezierPickerController: CubicBezierPickerController, - CubicBezierPickerView: CubicBezierPickerView, - CubicBezierPreviewView: CubicBezierPreviewView, - CubicBezierView: CubicBezierView, - FpsGraphBladeApi: FpsGraphBladeApi, - FpsGraphController: FpsGraphController, - FpsView: FpsView, - Fpswatch: Fpswatch, - Interval: Interval, - IntervalAssembly: IntervalAssembly, - IntervalConstraint: IntervalConstraint, - RadioCellApi: RadioCellApi, - RadioController: RadioController, - RadioGridApi: RadioGridApi, - RadioGridController: RadioGridController, - RadioView: RadioView, - RangeSliderController: RangeSliderController, - RangeSliderTextController: RangeSliderTextController, - RangeSliderTextView: RangeSliderTextView, - RangeSliderView: RangeSliderView, - TpRadioGridChangeEvent: TpRadioGridChangeEvent, - css: css, - id: id, - plugins: plugins - }); - - class NeuroSurfaceViewer { - constructor(container, width, height, config = {}, viewpoint = 'lateral') { - this.container = container; - this.width = width; - this.height = height; - this.config = { - ambientLightColor: 0x404040, - directionalLightColor: 0xffffff, - directionalLightIntensity: 0.5, - rotationSpeed: 2, - initialZoom: 4, - ...config - }; - this.viewpoint = viewpoint; - - this.scene = new Scene(); - this.camera = new PerspectiveCamera(75, this.width / this.height, 0.1, 1000); - this.renderer = new WebGLRenderer({ antialias: true }); - - this.setupRenderer(); - this.setupCamera(); - this.setupLighting(); - this.setupControls(); - - this.surfaces = new Map(); // Store multiple surfaces - - this.raycaster = new Raycaster(); - this.mouse = new Vector2(); - this.intersectionPoint = new Vector3(); - - this.dataRange = { min: 0, max: 500 }; // Initialize to default values - this.intensityRange = { range: { min: 0, max: 500 } }; - this.thresholdRange = { range: { min: 0, max: 0 } }; // Set default threshold to [0, 0] - - this.viewpoints = { - left_lateral: new Matrix4().set( - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - ), - left_medial: new Matrix4().set( - 0, 0, 1, 0, - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - ), - left_ventral: new Matrix4().set( - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, -1, 0, - 0, 0, 0, 1 - ), - left_posterior: new Matrix4().set( - 1, 0, 0, 0, - 0, 0, -1, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - ), - right_lateral: new Matrix4().set( - 0, 0, 1, 0, - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - ), - right_medial: new Matrix4().set( - 0, 0, -1, 0, - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - ), - right_ventral: new Matrix4().set( - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, -1, 0, - 0, 0, 0, 1 - ), - right_posterior: new Matrix4().set( - 1, 0, 0, 0, - 0, 0, -1, 0, - 0, 1, 0, 0, - 0, 0, 0, 1 - ) - }; - - this.setupTweakPane(); - this.setViewpoint(this.viewpoint); // Set the initial viewpoint - this.centerCamera(); // Center the camera after setting the viewpoint - - this.animate = this.animate.bind(this); - this.animate(); - } - - setupRenderer() { - this.renderer.setClearColor(0xffffff); // Set to white (0xffffff) - this.renderer.setSize(this.width, this.height); - this.renderer.setPixelRatio(window.devicePixelRatio); - this.container.appendChild(this.renderer.domElement); - } - - setupCamera() { - this.camera = new PerspectiveCamera(45, this.width / this.height, 0.1, 2000); - this.camera.position.z = 500; // Start further away - this.camera.lookAt(new Vector3(0, 0, 0)); - } - - setupLighting() { - this.ambientLight = new AmbientLight(this.config.ambientLightColor); - this.scene.add(this.ambientLight); - - this.directionalLight = new DirectionalLight( - this.config.directionalLightColor, - this.config.directionalLightIntensity - ); - this.directionalLight.position.set(1, 1, 1).normalize(); - this.scene.add(this.directionalLight); - - this.light = new PointLight(0xFFFFFF); - this.light.position.set(0, 0, 500); - this.scene.add(this.light); - } - - setupControls() { - this.controls = new TrackballControls(this.camera, this.renderer.domElement); - this.controls.rotateSpeed = this.config.rotationSpeed; - this.controls.zoomSpeed = 1.2; - this.controls.panSpeed = 0.8; - this.controls.noZoom = false; - this.controls.noPan = false; - this.controls.staticMoving = true; - this.controls.dynamicDampingFactor = 0.3; - } - - setupTweakPane() { - // Create a container for Tweakpane - const paneContainer = document.createElement('div'); - paneContainer.style.position = 'absolute'; - paneContainer.style.top = '10px'; - paneContainer.style.right = '10px'; - paneContainer.style.width = '250px'; - paneContainer.style.zIndex = '1000'; - this.container.appendChild(paneContainer); - - this.pane = new Pane({ - container: paneContainer, - title: 'NeuroSurface Controls', - expanded: true, - }); - - // Register the essentials plugin - this.pane.registerPlugin(EssentialsPlugin); - - // Set the width of the Tweakpane - this.pane.element.style.width = '100%'; - - // Lighting folder - const lightingFolder = this.pane.addFolder({ - title: 'Lighting', - expanded: false, - }); - - lightingFolder.addBinding(this.config, 'ambientLightColor', { - label: 'Ambient Light', - view: 'color', - }).on('change', (ev) => { - this.updateAmbientLight(ev.value); - }); - - lightingFolder.addBinding(this.config, 'directionalLightColor', { - label: 'Directional Light', - view: 'color', - }).on('change', (ev) => { - this.updateDirectionalLight(ev.value); - }); - - lightingFolder.addBinding(this.config, 'directionalLightIntensity', { - label: 'Light Intensity', - min: 0, - max: 1, - step: 0.01, - }).on('change', (ev) => { - this.updateDirectionalLightIntensity(ev.value); - }); - - // Camera folder - const cameraFolder = this.pane.addFolder({ - title: 'Camera', - expanded: false, - }); - - cameraFolder.addButton({ - title: 'Reset Camera', - }).on('click', () => { - this.resetCamera(); - }); - - // Color Map folder - const colorMapFolder = this.pane.addFolder({ - title: 'Color Map', - expanded: true, - }); - - // Add intensity range slider - this.intensityRangeControl = colorMapFolder.addBinding(this.intensityRange, 'range', { - label: 'Intensity Range', - min: this.dataRange.min, - max: this.dataRange.max, - step: 0.01, - }).on('change', this.updateIntensityRange.bind(this)); - - // Add threshold range slider - this.thresholdRangeControl = colorMapFolder.addBinding(this.thresholdRange, 'range', { - label: 'Threshold Range', - min: this.dataRange.min, - max: this.dataRange.max, - step: 0.01, - }).on('change', this.updateThresholdRange.bind(this)); - - // Viewpoint folder - const viewpointFolder = this.pane.addFolder({ - title: 'Viewpoint', - expanded: false, - }); - - this.viewpointState = { viewpoint: this.viewpoint }; - viewpointFolder.addBinding(this.viewpointState, 'viewpoint', { - label: 'Viewpoint', - options: { - lateral: 'lateral', - medial: 'medial', - ventral: 'ventral', - posterior: 'posterior', - }, - }).on('change', (ev) => { - this.setViewpoint(ev.value); - }); - } - - setViewpoint(viewpoint) { - let umat; - let hemisphere = 'left'; // Default to left hemisphere - - // Check if there are any surfaces and if the first one has a hemisphere property - const firstSurface = this.surfaces.values().next().value; - if (firstSurface && firstSurface.hemisphere) { - hemisphere = firstSurface.hemisphere; - } - - const fullViewpoint = `${hemisphere}_${viewpoint}`; - - if (this.viewpoints[fullViewpoint]) { - umat = this.viewpoints[fullViewpoint]; - } else { - console.warn(`Unknown viewpoint: ${fullViewpoint}`); - umat = new Matrix4().identity(); - } - - console.log('Setting viewpoint to:', viewpoint); - console.log('Current viewpoint state:', this.viewpointState); - console.log("umat", umat); - - // Calculate the bounding box of all surfaces - const box = new Box3(); - this.surfaces.forEach(surface => { - box.expandByObject(surface.mesh); - }); - const center = box.getCenter(new Vector3()); - const size = box.getSize(new Vector3()); - const maxDim = Math.max(size.x, size.y, size.z); - - // Set camera position based on umat - const distance = maxDim * this.config.initialZoom; // Adjust this multiplier as needed - const cameraPosition = new Vector3(0, 0, distance).applyMatrix4(umat); - this.camera.position.copy(cameraPosition.add(center)); - - // Set camera up vector - const up = new Vector3(0, 1, 0).applyMatrix4(umat); - this.camera.up.copy(up); - - // Set camera look at - this.camera.lookAt(center); - - // Update controls - this.controls.target.copy(center); - this.controls.update(); - - this.viewpoint = viewpoint; - if (this.viewpointState) { - this.viewpointState.viewpoint = viewpoint; - } - - this.render(); - } - - updateColormap(presetName) { - this.surfaces.forEach(surface => { - if (surface instanceof ColorMappedNeuroSurface) { - surface.setColorMap(ColorMap.fromPreset(presetName)); - surface.updateColors(); - } - }); - this.render(); - } - - updateAmbientLight(color) { - if (this.ambientLight) { - this.ambientLight.color.setHex(color); - this.render(); - } - } - - updateDirectionalLight(color) { - if (this.directionalLight) { - this.directionalLight.color.setHex(color); - this.render(); - } - } - - updateDirectionalLightIntensity(intensity) { - if (this.directionalLight) { - this.directionalLight.intensity = intensity; - this.render(); - } - } - - updateIntensityRange() { - console.log('NeuroSurfaceViewer: Updating intensity range', [this.intensityRange.range.min, this.intensityRange.range.max]); - this.surfaces.forEach(surface => { - if (surface instanceof ColorMappedNeuroSurface) { - surface.colorMap.setRange([this.intensityRange.range.min, this.intensityRange.range.max]); - } - }); - // The surface should update automatically due to the event listener - } - - updateThresholdRange() { - console.log('NeuroSurfaceViewer: Updating threshold range', [this.thresholdRange.range.min, this.thresholdRange.range.max]); - this.surfaces.forEach(surface => { - if (surface instanceof ColorMappedNeuroSurface) { - surface.colorMap.setThreshold([this.thresholdRange.range.min, this.thresholdRange.range.max]); - } - }); - // The surface should update automatically due to the event listener - } - - resetCamera() { - if (this.camera && this.controls) { - this.setViewpoint(this.viewpoint); // Reset to the current viewpoint - this.render(); - } - } - - addSurface(surface, id) { - console.log('Adding surface:', surface, 'with id:', id); - this.surfaces.set(id, surface); - if (!surface.mesh) { - console.warn('Surface mesh not created. Creating now.'); - surface.createMesh(); - } - this.scene.add(surface.mesh); - - if (surface instanceof ColorMappedNeuroSurface) { - console.log('Updating data range for ColorMappedNeuroSurface'); - this.updateDataRange(surface.data); - this.updateRangeControls(); - } - - if (this.surfaces.size === 1) { - this.resetCamera(); // Center the camera when the first surface is added - } - this.render(); - } - - updateDataRange(data) { - const min = Math.min(...data); - const max = Math.max(...data); - - this.dataRange.min = min; - this.dataRange.max = max; - - // Update intensity range to match data range - this.intensityRange.range.min = min; - this.intensityRange.range.max = max; - - // Keep threshold range at [0, 0] - this.thresholdRange.range.min = 0; - this.thresholdRange.range.max = 0; - - this.updateRangeControls(); - } - - updateRangeControls() { - // Update intensity range control - this.intensityRangeControl.min = this.dataRange.min; - this.intensityRangeControl.max = this.dataRange.max; - this.intensityRangeControl.value = this.intensityRange.range; - - // Update threshold range control - this.thresholdRangeControl.min = this.dataRange.min; - this.thresholdRangeControl.max = this.dataRange.max; - this.thresholdRangeControl.value = this.thresholdRange.range; - - // Refresh the controls - this.intensityRangeControl.refresh(); - this.thresholdRangeControl.refresh(); - } - - removeSurface(id) { - const surface = this.surfaces.get(id); - if (surface) { - this.scene.remove(surface.mesh); - this.surfaces.delete(id); - } - } - - onWindowResize(width, height) { - this.width = width; - this.height = height; - this.camera.aspect = this.width / this.height; - this.camera.updateProjectionMatrix(); - this.renderer.setSize(this.width, this.height); - } - - animate() { - requestAnimationFrame(this.animate); - this.controls.update(); - this.render(); - } - - render() { - if (this.renderer && this.scene && this.camera) { - this.renderer.render(this.scene, this.camera); - } - } - - centerCamera() { - if (this.surfaces.size === 0) return; // No surfaces to center on - - const box = new Box3(); - this.surfaces.forEach(surface => { - box.expandByObject(surface.mesh); - }); - - const center = box.getCenter(new Vector3()); - const size = box.getSize(new Vector3()); - - const maxDim = Math.max(size.x, size.y, size.z); - const fov = this.camera.fov * (Math.PI / 180); - let cameraDistance = Math.abs(maxDim / 2 / Math.tan(fov / 2)); - - cameraDistance *= this.config.initialZoom; // Add some distance for better view - - const direction = this.camera.position.clone().sub(this.controls.target).normalize(); - this.camera.position.copy(center.clone().add(direction.multiplyScalar(cameraDistance))); - this.controls.target.copy(center); - - this.camera.near = cameraDistance / 100; - this.camera.far = cameraDistance * 100; - this.camera.updateProjectionMatrix(); - - this.controls.update(); - } - - // Add this method to the NeuroSurfaceViewer class - - setData(id, newData) { - const surface = this.surfaces.get(id); - if (surface && surface instanceof ColorMappedNeuroSurface) { - surface.setData(newData); - this.updateDataRange(newData); - this.updateRangeControls(); - surface.updateColors(); - this.render(); - console.log(`Updated data for surface with id: ${id}`); - } else { - console.warn(`No ColorMappedNeuroSurface found with id: ${id}`); - } - } - - setVertexColors(id, colors) { - const surface = this.surfaces.get(id); - if (surface && surface instanceof VertexColoredNeuroSurface) { - surface.setColors(colors); - this.render(); - console.log(`Updated colors for surface with id: ${id}`); - } else { - console.warn(`No VertexColoredNeuroSurface found with id: ${id}`); - } - } - - setRotationSpeed(speed) { - this.config.rotationSpeed = speed; - if (this.controls) { - this.controls.rotateSpeed = speed; - } - } - - setInitialZoom(zoom) { - this.config.initialZoom = zoom; - if (this.camera) { - const direction = this.camera.position.clone().sub(this.controls.target).normalize(); - const distance = this.camera.position.distanceTo(this.controls.target); - this.camera.position.copy(this.controls.target.clone().add(direction.multiplyScalar(distance / zoom))); - this.camera.updateProjectionMatrix(); - this.controls.update(); - } - } - } - - // Optionally, you can also attach these to the global window object - // This can be useful if you need to access these classes directly in the browser - if (typeof window !== 'undefined') { - window.neurosurface = { - NeuroSurfaceViewer, - SurfaceGeometry, - NeuroSurface, - ColorMappedNeuroSurface, - VertexColoredNeuroSurface, - THREE - }; - } - - console.log('Neurosurface module initialized'); - - exports.ColorMappedNeuroSurface = ColorMappedNeuroSurface; - exports.NeuroSurface = NeuroSurface; - exports.NeuroSurfaceViewer = NeuroSurfaceViewer; - exports.SurfaceGeometry = SurfaceGeometry; - exports.THREE = THREE; - exports.VertexColoredNeuroSurface = VertexColoredNeuroSurface; - - Object.defineProperty(exports, '__esModule', { value: true }); - - return exports; - -})({}); + setData(newData) { + const isArray = Array.isArray(newData) || ArrayBuffer.isView(newData); + if (!isArray) { + console.error('setData expects an array or typed array of numbers'); + return; + } + if (newData.length !== this.data.length) { + console.error(`New data length (${newData.length}) does not match the current data length (${this.data.length})`); + return; + } + this.data = ArrayBuffer.isView(newData) ? new Float32Array(newData) : Float32Array.from(newData); + this.updateColors(); + } + setColors(newColors) { + if (!Array.isArray(newColors)) { + console.error('setColors expects an array of color strings'); + return; + } + if (newColors.length !== this.indices.length) { + console.error(`Colors array length (${newColors.length}) does not match the number of indices (${this.indices.length})`); + return; + } + + this.colors = new Float32Array(newColors.length * 3); + for (let i = 0; i < newColors.length; i++) { + if (typeof newColors[i] !== 'string') { + console.error(`Color at index ${i} is not a valid string`); + return; + } + const color = new Color(newColors[i]); + this.colors[i * 3] = color.r; + this.colors[i * 3 + 1] = color.g; + this.colors[i * 3 + 2] = color.b; + } + this.updateColors(); + } diff --git a/inst/htmlwidgets/neurosurface/src/classes.js b/inst/htmlwidgets/neurosurface/src/classes.js index b4df5d6..f11aa35 100644 --- a/inst/htmlwidgets/neurosurface/src/classes.js +++ b/inst/htmlwidgets/neurosurface/src/classes.js @@ -315,11 +315,16 @@ export class ColorMappedNeuroSurface extends NeuroSurface { } setData(newData) { + const isArray = Array.isArray(newData) || ArrayBuffer.isView(newData); + if (!isArray) { + console.error('setData expects an array or typed array of numbers'); + return; + } if (newData.length !== this.data.length) { - console.error('New data length does not match the current data length'); + console.error(`New data length (${newData.length}) does not match the current data length (${this.data.length})`); return; } - this.data = newData; + this.data = ArrayBuffer.isView(newData) ? new Float32Array(newData) : Float32Array.from(newData); this.updateColors(); } } @@ -331,8 +336,21 @@ export class VertexColoredNeuroSurface extends NeuroSurface { } setColors(newColors) { + if (!Array.isArray(newColors)) { + console.error('setColors expects an array of color strings'); + return; + } + if (newColors.length !== this.indices.length) { + console.error(`Colors array length (${newColors.length}) does not match the number of indices (${this.indices.length})`); + return; + } + this.colors = new Float32Array(newColors.length * 3); for (let i = 0; i < newColors.length; i++) { + if (typeof newColors[i] !== 'string') { + console.error(`Color at index ${i} is not a valid string`); + return; + } const color = new THREE.Color(newColors[i]); this.colors[i * 3] = color.r; this.colors[i * 3 + 1] = color.g;