diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 7754020..9e4e16c 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -29,10 +29,11 @@ rm compiler-latest.zip popd ``` -Note: on some systems, `gem` commands might require administrator privileges: +Note: on some systems, `gem` and `npm install -g` commands might require administrator privileges: ```bash sudo gem install sass sudo gem install compass +sudo npm install -g grunt-cli ``` On recent MacOS, you might need to install `compass` to a different directory if using pre-installed ruby: @@ -40,6 +41,16 @@ On recent MacOS, you might need to install `compass` to a different directory if sudo gem install -n /usr/local/bin compass ``` +On WSL/ubuntu, `ruby-dev` is required for sass installation. +``` +sudo apt-get install ruby-dev +``` + +Java JRE is required for Google Closure Compiler: +``` +sudo apt install openjdk-8-jre-headless +``` + Build the project ----------------- diff --git a/README.md b/README.md index b7d5e07..9023a7e 100755 --- a/README.md +++ b/README.md @@ -67,23 +67,22 @@ If you're interested in older releases, checkout [the Tags tab][download-link-ta Supported browsers ------------------ - -| OS | Browser | Panorama viewing | Video playback | Video streaming (HLS) | Legacy VR⁵ | WebVR | Headsets supported | -| ------- | --------------------------- |:----------------:|:--------------:|:---------------------:|:----------:|:-----:| ------------------------------------------ | -| Windows | Google Chrome | ✔ | ✔ | ✔ | | ✔¹ | Oculus, Vive, Windows Mixed Reality⁶ | -| Windows | Mozilla Firefox | ✔ | ✔ | ✔ | | ✔² | Oculus, OSVR, Vive, Windows Mixed Reality⁶ | -| Windows | Microsoft Edge | ✔ | ✔ | ✔ | | ✔ | Windows Mixed Reality, Hololens⁷ | -| Windows | Internet Explorer (11+) | ✔ | ✔ | ✔ | | | | -| Mac OS | Safari | ✔ | ✔⁴ | ✔ | | | | -| Mac OS | Google Chrome | ✔ | ✔ | ✔ | | | | -| Mac OS | Mozilla Firefox | ✔ | ✔ | ✔ | | | | -| Android | Mozilla Firefox | ✔ | ✔ | ✔ | | | | -| Android | Google Chrome | ✔ | ✔ | ✔ | ✔ | ✔³ | Cardboard | -| Android | Samsung Internet | ✔ | ✔ | | ✔ | | Cardboard | -| Android | Samsung Internet for GearVR | ✔ | ✔ | ✔ | | ✔ | GearVR | -| iOS | Safari | ✔ | ✔ | | ✔ | | Cardboard | -| iOS | Google Chrome | ✔ | ✔ | | ✔ | | Cardboard | -| iOS | Mozilla Firefox | ✔ | ✔ | | | | | +| OS | Browser | Panorama viewing | Video playback | Video streaming (HLS) | WebXR | Legacy VR⁵ | legacy WebVR | Headsets supported | +| ------- | --------------------------- |:----------------:|:--------------:|:---------------------:|:-----:|:----------:|:------------:| ------------------------------------------ | +| Windows | Google Chrome | ✔ | ✔ | ✔ | ✔ | | ✔¹ | Oculus, Vive, Windows Mixed Reality⁶ | +| Windows | Mozilla Firefox | ✔ | ✔ | ✔ | ✔⁸ | | ✔² | Oculus, OSVR, Vive, Windows Mixed Reality⁶ | +| Windows | Microsoft Edge | ✔ | ✔ | ✔ | ✔ | | ✔ | Windows Mixed Reality, Hololens⁷ | +| Windows | Internet Explorer (11+) | ✔ | ✔ | ✔ | | | | | +| Mac OS | Safari | ✔ | ✔⁴ | ✔ | | | | | +| Mac OS | Google Chrome | ✔ | ✔ | ✔ | | | | | +| Mac OS | Mozilla Firefox | ✔ | ✔ | ✔ | | | | | +| Android | Google Chrome | ✔ | ✔ | ✔ | ✔ | ✔ | ✔³ | Cardboard | +| Android | Mozilla Firefox | ✔ | ✔ | ✔ | | | | | +| Android | Samsung Internet | ✔ | ✔ | | | ✔ | | Cardboard | +| Android | Samsung Internet for GearVR | ✔ | ✔ | ✔ | ✔ | | ✔ | GearVR | +| iOS | Safari | ✔ | ✔ | | | ✔ | | Cardboard | +| iOS | Google Chrome | ✔ | ✔ | | | ✔ | | Cardboard | +| iOS | Mozilla Firefox | ✔ | ✔ | | | | | | ¹ - With a [dedicated WebVR Chromium build][webvr-chromium] or [Chrome Canary][webvr-chrome-canary] ² - With [Firefox Nightly][webvr-firefox] @@ -91,7 +90,10 @@ Supported browsers ⁴ - Movies must be on the same domain ([broken CORS implementation][video-does-not-work]) ⁵ - Split screen with orientation sensor support (basic Cardboard) ⁶ - Windows Mixed Reality support via Microsoft's Windows Mixed Reality for SteamVR -⁷ - Requires enabling WebVR in `about:flags` +⁷ - Requires enabling WebVR in `about:flags` +⁸ - Requires enabling WebXR in `about:flags` or using Firefox Reality + +Note: some of these test results might be out of date. [video-does-not-work]: #video-does-not-work @@ -136,6 +138,7 @@ Installation Don't forget to set the correct paths. 3. [Configure the video player][configuration] 4. [Encode media][media-preparation-guide] +5. Make sure you serve the player and the page you're hosting it from on HTTPS. WebXR and gyroscope (orientation) features are disabled on non secure origins. Host media from the same server or enable [CORS][cors]. [configuration]: #configuration [media-preparation-guide]: #media-preparation-guide @@ -530,7 +533,7 @@ BIVROST Analytics for VR integration ------------------------------------ The 360WebPlayer has a built-in support for gathering user analytics, just like the other BIVROST players. -For more information about BIVROST Analytics for VR, please contact us at [contact@bivrost360.com][email-sales]. +For more information about BIVROST Analytics for VR, please contact us at [contact@bivrost.pro][email-sales]. Analytics works only with videos. It does not work with static images (panoramas) or with infinite live streams. @@ -654,6 +657,7 @@ You can distinguish between the sessions with the `lookprovider` field of the se Look providers generated by the player: * `bivrost:360WebPlayer:main-display` - gathered by the mono renderer - the classical desktop or mobile mode. * `bivrost:360WebPlayer:webvr` - gathered by the WebVR view. +* `bivrost:360WebPlayer:webxr` - gathered by the WebXR view. * `bivrost:360WebPlayer:legacy-stereo` - gathered by the legacy Stereo view (Cardboard support). @@ -671,10 +675,24 @@ User Guide * ` [ `, ` ] ` - scroll movie by 5 seconds, forwards or backwards. * ` + `, ` - ` - zoom in/out (not available in VR mode). +### Virtual Reality on desktop and mobile with WebXR -### Virtual Reality on desktop and mobile with WebVR +WebXR is the new browser Virtual Reality standard. It has built in support on major platforms including: -At the time of writing, WebVR is supported by Microsoft Edge, [Firefox Nightly][webvr-firefox], special [Windows builds of Chromium][webvr-chromium] and [Chrome Canary][webvr-chrome-canary], Google Chrome on Android with Cardboard (after enabling WebVR in `chrome://flags/#enable-webvr`) and [Samsung Internet Browser for Gear VR][webvr-samsung]. +- Chrome for Windows +- Chrome for Android +- Microsoft Edge (Chromium) for Windows 10 +- Firefox Reality + +When you have a supported platform, an headset button will be visible in 360WebPlayer - press it to enter VR. + + +### Virtual Reality on desktop and mobile with legacy WebVR support + +WebXR is currently disabled in all new browsers and is superseded by WebXR. +It has been left as a legacy fallback for devices that still might support it. + +WebVR was supported by Microsoft Edge, [Firefox Nightly][webvr-firefox], special [Windows builds of Chromium][webvr-chromium] and [Chrome Canary][webvr-chrome-canary], Google Chrome on Android with Cardboard (after enabling WebVR in `chrome://flags/#enable-webvr`) and [Samsung Internet Browser for Gear VR][webvr-samsung]. When you have a supported platform, an headset button will be visible in 360WebPlayer - press it to enter VR. @@ -690,6 +708,9 @@ For more platform specific instructions look at the [WebVR][webvr] website. ### Virtual Reality on mobile with legacy Google Cardboard support +Most current Android devices are able to use WebXR which has better overall user experience. +This is a legacy fallback for mobile devices that have orientation sensors but do not support WebXR. + You can use the Bivrost 360WebPlayer with Google Cardboard and its many clones with a simple split screen. Just press the "headset" button to go to VR mode. Contrary to most players, you don't have to enable screen rotation for 360WebPlayer to work properly in cardboard mode. The phone can be in both landscape or portrait mode. @@ -726,6 +747,10 @@ Either your webserver doesn't support [Content-Range][content-range] or there ar [content-range]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16 +### WebXR or legacy cardboard VR does not work on my page, but does work on other pages + +Force HTTPS on all pages embedding the player. Orientation events, WebXR and other features do not work on non-secure origins. +This is a standards-backed security requirement implemented by current browsers. ### Where can I submit feature requests or bug reports? Where can I find the unminified version? @@ -753,12 +778,14 @@ Please [contact sales at contact@bivrost360.com][email-sales] for more details. License ------- -Terms and conditions are [available in a separate document (english)](LICENSE.md) [(polish)](LICENSE-polish.md). +This software is free and can be used only for noncommercial purposes. To purchase the commercial license read the terms and contact us: [contact@bivrost.pro][email-sales] + +Terms and conditions are [available in a separate document [English]](LICENSE.md) [[Polish]](LICENSE-polish.md). If you want to remove or replace our branding, are unsure about which license applies to you, please [contact us for help and additional licensing options][email-sales]. [section-license]: #License -[email-sales]: mailto:contact@bivrost360.com +[email-sales]: mailto:contact@bivrost.pro ### Third party libraries @@ -778,7 +805,7 @@ The BIVROST 360WebPlayer can be optionaly made to use third party libraries: Changelog --------- -* 2016-03-14: initial public release +* 2016-03-14: initial public release (version 1.0) * 2016-09-21: WebVR 1.1 support * 2016-12-21: GearVR support, stereo UI * 2016-12-30: Documentation update @@ -786,5 +813,5 @@ Changelog * 2018-01-26: Move to GitLab, updated documentation * 2018-08-08: Moved back to GitHub, updated logo * 2019-04-05: Updated logo -* 2020-07-16: Fixed issues with iOS 13 fullscreen and gyroscope -* 2020-08-06: License updated +* 2020-07-16: Fixed issues with iOS 13 fullscreen and gyroscope (version 1.1) +* 2020-08-06: WebXR support, license updated (version 1.2) diff --git a/scripts.json b/scripts.json index 85a2535..afd1d6a 100644 --- a/scripts.json +++ b/scripts.json @@ -24,6 +24,7 @@ "src/bivrost-renderer-mono.js", "src/bivrost-renderer-stereo.js", "src/bivrost-renderer-webvr.js", + "src/bivrost-renderer-webxr.js", "src/IEVideoTexture.js", "src/bivrost-analytics.js" ] \ No newline at end of file diff --git a/src/bivrost-input.js b/src/bivrost-input.js index 20f64c6..e33cb76 100644 --- a/src/bivrost-input.js +++ b/src/bivrost-input.js @@ -273,7 +273,8 @@ this.__initGyroscope(player); - // WebVR support + // WebXR and legacy WebVR support + this.__initWebXR(player); this.__initWebVR(player); }; @@ -674,6 +675,50 @@ + /// REGION: WebXR + { + Bivrost.Input.prototype.xrAvailable = false; + // Bivrost.Input.prototype.vrDisplaySize = { x:undefined, y:undefined }; + + /** + * Initiates WebXR support + * @param {Bivrost.Input} input + * @param {Bivrost.Player} player + */ + Bivrost.Input.prototype.__initWebXR=function(input, player) { + if(!navigator.xr) { + log("WebVR: WebVR not supported"); + return; + } + + var input=this; + + navigator.xr.isSessionSupported('immersive-vr').then(function(supported) { + if (supported) { + // input.vrDisplay = displays[0]; + + // var eyeLeft = input.vrDisplay.getEyeParameters("left"); + // var eyeRight = input.vrDisplay.getEyeParameters("right"); + + // var width = eyeLeft.renderWidth + eyeRight.renderWidth; + // var height = Math.max(eyeLeft.renderWidth, eyeRight.renderWidth); + + // input.vrDisplaySize.x=width; + // input.vrDisplaySize.y=height; + + // log("WebVR: Found VR Display with size: "+width+"x"+height); + // input.onInputMethodAdded.publish(input); + input.xrAvailable = true; + log("WebXR: supported") + } + else { + log("WebXR: No VR Displays found"); + } + }); + }; + } + + /// REGION: Gyroscope { /** diff --git a/src/bivrost-player.js b/src/bivrost-player.js index 3e203fe..9c66e54 100644 --- a/src/bivrost-player.js +++ b/src/bivrost-player.js @@ -68,6 +68,9 @@ // renderer this.webglRenderer=new THREE.WebGLRenderer({ antialias: true }); + this.webglRenderer.xr.enabled = true; + this.webglRenderer.xr.setReferenceSpaceType( 'local' ); + this.webglRenderer.setClearColor(0x000000, 1); // iOS doesn't have this set up as proper default container.appendChild(this.webglRenderer.domElement); @@ -100,9 +103,9 @@ function mainloopBound() { var dt=clock.getDelta(); thisRef.mainLoop(dt); - requestAnimationFrame(mainloopBound); }; - requestAnimationFrame(mainloopBound); + this.webglRenderer.setAnimationLoop(mainloopBound); + }; @@ -297,6 +300,7 @@ Bivrost.Player.prototype.vrModeEnterOrCycle=function() { var player=this; var vrModes=[ + Bivrost.Renderer.WebXR, Bivrost.Renderer.WebVR, Bivrost.Renderer.Stereo ].filter(function(r) { return r.shouldWork(player); }); @@ -310,12 +314,19 @@ vrMode=vrModes[0]; log("selecting default VR mode"); } - // already in vr mode - toggle next available mode + // already in vr mode - reset to mono else { - var index=(vrModes.indexOf(this.renderer.__proto__) + 1) % vrModes.length; - vrMode=vrModes[index]; - log("selecting next VR mode"); + log("back to mono"); + this.vrExit(); + return; } + + // // already in vr mode - toggle next available mode + // else { + // var index=(vrModes.indexOf(this.renderer.__proto__) + 1) % vrModes.length; + // vrMode=vrModes[index]; + // log("selecting next VR mode"); + // } this.renderer=new vrMode(this); }; diff --git a/src/bivrost-renderer-webxr.js b/src/bivrost-renderer-webxr.js new file mode 100644 index 0000000..fa42678 --- /dev/null +++ b/src/bivrost-renderer-webxr.js @@ -0,0 +1,147 @@ +/* global Bivrost, THREE */ +"use strict"; + +// https://github.com/immersive-web/webxr-samples/blob/master/vr-barebones.html +// https://github.com/immersive-web/webxr/blob/master/webvr-migration.md + +(function() { + + /** + * Logging helper + * @private + * @param {...object} vargs + */ + function log(/*vargs...*/) { Bivrost.log("Bivrost.Renderer.WebXR", arguments); }; + + + Bivrost.Renderer.WebXR = function(player) { + Bivrost.Renderer.call(this); + }; + Bivrost.extend(Bivrost.Renderer.WebXR, Bivrost.Renderer); + + + /** + * @const + */ + Bivrost.Renderer.WebXR.PLATFORM_NAME = "WebXR"; + + + Bivrost.Renderer.WebXR.prototype.init = function(player) { + Bivrost.Renderer.prototype.init.call(this, player); + + var thisRef = this; + var sessionInit = { optionalFeatures: [ 'local-floor', 'bounded-floor' ] }; + + navigator.xr.requestSession('immersive-vr', sessionInit).then(function(session) + { + // Called either when the user has explicitly ended the session by calling + // session.end() or when the UA has ended the session for any reason. + // At this point the session object is no longer usable and should be + // discarded. + function onSessionEnded(event) { + session.removeEventListener("end", onSessionEnded ); + thisRef.player.vrExit(); + } + + // Listen for the sessions 'end' event so we can respond if the user + // or UA ends the session for any reason. + session.addEventListener('end', onSessionEnded); + + player.webglRenderer.xr.setSession( session ); + + thisRef.xrSession = session; + + log("Started WebXR"); + + }); + }; + + + Bivrost.Renderer.WebXR.prototype.destroy = function(player) { + Bivrost.Renderer.prototype.destroy.call(this, player); + + if(this.xrSession) + this.xrSession.end(); + + this.vrScene.dispose(); + this.vrScene = null; + this.vrCamera = null; + }; + + /** + * MONO renderer on the main display + * @param {THREE.WebGLRenderer} webglRenderer + * @param {Bivrost.View} view + * @returns {undefined} + */ + Bivrost.Renderer.WebXR.prototype.render = function(webglRenderer, view) { + var firstFrame = false; + // scene data not yet copied from normal renderer + if(!this.vrScene) { + firstFrame = true; + this.vrScene = new THREE.Scene(); + this.vrSceneOrigin = new THREE.Group(); + this.vrScene.add(this.vrSceneOrigin); + for(var i = 0; i < view.leftScene.children.length; i++) + { + if(view.leftScene.children[i] == view.leftCamera) continue; + var mesh = view.leftScene.children[i].clone(); + mesh.layers.set(1); + //if(!view.enablePositionalCamera) mesh.scale + this.vrSceneOrigin.add(mesh); + } + for(var i = 0; i < view.rightScene.children.length; i++) + { + if(view.rightScene.children[i] == view.rightCamera) continue; + var mesh = view.rightScene.children[i].clone(); + mesh.layers.set(2); + this.vrSceneOrigin.add(mesh); + } + this.vrCamera = view.leftCamera.clone(); + this.vrCamera.layers.enable(1); // render left view when no stereo available + this.vrScene.add(this.vrCamera); + this.vrTranslation = new THREE.Vector3(); + this.vrRotation = new THREE.Quaternion(); + this.vrCameraPositionHelper = new THREE.Mesh(); + this.vrCamera.add(this.vrCameraPositionHelper); + log("WebXR lazy init"); + } + + // classical renderer only if WebXR has a separate screen + // TODO: check for hasExternalDisplay WebVR equivalent + if(this.vrCamera) { + view.leftCamera.rotation.copy(this.vrCamera.rotation); + view.leftCamera.position.copy(this.vrCamera.position); + } + + this.vrCameraPositionHelper.getWorldPosition(this.vrTranslation); + this.vrCameraPositionHelper.getWorldQuaternion(this.vrRotation); + + if(firstFrame || !view.enablePositionalCamera) + { + // TODO: rotation? + + this.vrSceneOrigin.position.set(this.vrTranslation.x, this.vrTranslation.y, this.vrTranslation.z); + } + + webglRenderer.render(this.vrScene, this.vrCamera); + }; + + + Bivrost.Renderer.WebXR.prototype.vrLeftCamera=null; + Bivrost.Renderer.WebXR.prototype.vrRightCamera=null; + Bivrost.Renderer.WebXR.prototype.vrLeftScene=null; + Bivrost.Renderer.WebXR.prototype.vrRightScene=null; + + + Bivrost.Renderer.WebXR.shouldWork = function(player) { return !!player.input.xrAvailable; }; + + + Bivrost.Renderer.WebXR.prototype.fullscreenChanged=function(isFullscreen) { + // if this is a reused renderer and fullscreen was turned off + if(this.vrRenderer === this.player.webglRenderer && !isFullscreen) { + this.player.vrExit(); + } + }; + +})(); \ No newline at end of file diff --git a/src/three.js b/src/three.js index fc14a17..e4b04bf 100644 --- a/src/three.js +++ b/src/three.js @@ -1,7 +1,7 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : - (factory((global.THREE = {}))); + (global = global || self, factory(global.THREE = {})); }(this, (function (exports) { 'use strict'; // Polyfills @@ -61,31 +61,27 @@ // Missing in IE // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign - ( function () { + Object.assign = function ( target ) { - Object.assign = function ( target ) { + if ( target === undefined || target === null ) { - if ( target === undefined || target === null ) { + throw new TypeError( 'Cannot convert undefined or null to object' ); - throw new TypeError( 'Cannot convert undefined or null to object' ); - - } - - var output = Object( target ); + } - for ( var index = 1; index < arguments.length; index ++ ) { + var output = Object( target ); - var source = arguments[ index ]; + for ( var index = 1; index < arguments.length; index ++ ) { - if ( source !== undefined && source !== null ) { + var source = arguments[ index ]; - for ( var nextKey in source ) { + if ( source !== undefined && source !== null ) { - if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) { + for ( var nextKey in source ) { - output[ nextKey ] = source[ nextKey ]; + if ( Object.prototype.hasOwnProperty.call( source, nextKey ) ) { - } + output[ nextKey ] = source[ nextKey ]; } @@ -93,117 +89,30 @@ } - return output; - - }; - - } )(); - - } - - /** - * https://github.com/mrdoob/eventdispatcher.js/ - */ - - function EventDispatcher() {} - - Object.assign( EventDispatcher.prototype, { - - addEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) this._listeners = {}; - - var listeners = this._listeners; - - if ( listeners[ type ] === undefined ) { - - listeners[ type ] = []; - - } - - if ( listeners[ type ].indexOf( listener ) === - 1 ) { - - listeners[ type ].push( listener ); - - } - - }, - - hasEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) return false; - - var listeners = this._listeners; - - return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; - - }, - - removeEventListener: function ( type, listener ) { - - if ( this._listeners === undefined ) return; - - var listeners = this._listeners; - var listenerArray = listeners[ type ]; - - if ( listenerArray !== undefined ) { - - var index = listenerArray.indexOf( listener ); - - if ( index !== - 1 ) { - - listenerArray.splice( index, 1 ); - - } - } - }, - - dispatchEvent: function ( event ) { - - if ( this._listeners === undefined ) return; - - var listeners = this._listeners; - var listenerArray = listeners[ event.type ]; - - if ( listenerArray !== undefined ) { - - event.target = this; - - var array = listenerArray.slice( 0 ); - - for ( var i = 0, l = array.length; i < l; i ++ ) { - - array[ i ].call( this, event ); - - } - - } + return output; - } + }; - } ); + } - var REVISION = '98'; - var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 }; + var REVISION = '119'; + var MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; + var TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; var CullFaceNone = 0; var CullFaceBack = 1; var CullFaceFront = 2; var CullFaceFrontBack = 3; - var FrontFaceDirectionCW = 0; - var FrontFaceDirectionCCW = 1; var BasicShadowMap = 0; var PCFShadowMap = 1; var PCFSoftShadowMap = 2; + var VSMShadowMap = 3; var FrontSide = 0; var BackSide = 1; var DoubleSide = 2; var FlatShading = 1; var SmoothShading = 2; - var NoColors = 0; - var FaceColors = 1; - var VertexColors = 2; var NoBlending = 0; var NormalBlending = 1; var AdditiveBlending = 2; @@ -240,24 +149,29 @@ var NoToneMapping = 0; var LinearToneMapping = 1; var ReinhardToneMapping = 2; - var Uncharted2ToneMapping = 3; - var CineonToneMapping = 4; + var CineonToneMapping = 3; + var ACESFilmicToneMapping = 4; + var CustomToneMapping = 5; + var UVMapping = 300; var CubeReflectionMapping = 301; var CubeRefractionMapping = 302; var EquirectangularReflectionMapping = 303; var EquirectangularRefractionMapping = 304; - var SphericalReflectionMapping = 305; var CubeUVReflectionMapping = 306; var CubeUVRefractionMapping = 307; var RepeatWrapping = 1000; var ClampToEdgeWrapping = 1001; var MirroredRepeatWrapping = 1002; var NearestFilter = 1003; + var NearestMipmapNearestFilter = 1004; var NearestMipMapNearestFilter = 1004; + var NearestMipmapLinearFilter = 1005; var NearestMipMapLinearFilter = 1005; var LinearFilter = 1006; + var LinearMipmapNearestFilter = 1007; var LinearMipMapNearestFilter = 1007; + var LinearMipmapLinearFilter = 1008; var LinearMipMapLinearFilter = 1008; var UnsignedByteType = 1009; var ByteType = 1010; @@ -280,6 +194,12 @@ var DepthFormat = 1026; var DepthStencilFormat = 1027; var RedFormat = 1028; + var RedIntegerFormat = 1029; + var RGFormat = 1030; + var RGIntegerFormat = 1031; + var RGBIntegerFormat = 1032; + var RGBAIntegerFormat = 1033; + var RGB_S3TC_DXT1_Format = 33776; var RGBA_S3TC_DXT1_Format = 33777; var RGBA_S3TC_DXT3_Format = 33778; @@ -289,6 +209,8 @@ var RGBA_PVRTC_4BPPV1_Format = 35842; var RGBA_PVRTC_2BPPV1_Format = 35843; var RGB_ETC1_Format = 36196; + var RGB_ETC2_Format = 37492; + var RGBA_ETC2_EAC_Format = 37496; var RGBA_ASTC_4x4_Format = 37808; var RGBA_ASTC_5x4_Format = 37809; var RGBA_ASTC_5x5_Format = 37810; @@ -303,6 +225,21 @@ var RGBA_ASTC_10x10_Format = 37819; var RGBA_ASTC_12x10_Format = 37820; var RGBA_ASTC_12x12_Format = 37821; + var RGBA_BPTC_Format = 36492; + var SRGB8_ALPHA8_ASTC_4x4_Format = 37840; + var SRGB8_ALPHA8_ASTC_5x4_Format = 37841; + var SRGB8_ALPHA8_ASTC_5x5_Format = 37842; + var SRGB8_ALPHA8_ASTC_6x5_Format = 37843; + var SRGB8_ALPHA8_ASTC_6x6_Format = 37844; + var SRGB8_ALPHA8_ASTC_8x5_Format = 37845; + var SRGB8_ALPHA8_ASTC_8x6_Format = 37846; + var SRGB8_ALPHA8_ASTC_8x8_Format = 37847; + var SRGB8_ALPHA8_ASTC_10x5_Format = 37848; + var SRGB8_ALPHA8_ASTC_10x6_Format = 37849; + var SRGB8_ALPHA8_ASTC_10x8_Format = 37850; + var SRGB8_ALPHA8_ASTC_10x10_Format = 37851; + var SRGB8_ALPHA8_ASTC_12x10_Format = 37852; + var SRGB8_ALPHA8_ASTC_12x12_Format = 37853; var LoopOnce = 2200; var LoopRepeat = 2201; var LoopPingPong = 2202; @@ -312,6 +249,8 @@ var ZeroCurvatureEnding = 2400; var ZeroSlopeEnding = 2401; var WrapAroundEnding = 2402; + var NormalAnimationBlendMode = 2500; + var AdditiveAnimationBlendMode = 2501; var TrianglesDrawMode = 0; var TriangleStripDrawMode = 1; var TriangleFanDrawMode = 2; @@ -328,45 +267,151 @@ var TangentSpaceNormalMap = 0; var ObjectSpaceNormalMap = 1; + var ZeroStencilOp = 0; + var KeepStencilOp = 7680; + var ReplaceStencilOp = 7681; + var IncrementStencilOp = 7682; + var DecrementStencilOp = 7683; + var IncrementWrapStencilOp = 34055; + var DecrementWrapStencilOp = 34056; + var InvertStencilOp = 5386; + + var NeverStencilFunc = 512; + var LessStencilFunc = 513; + var EqualStencilFunc = 514; + var LessEqualStencilFunc = 515; + var GreaterStencilFunc = 516; + var NotEqualStencilFunc = 517; + var GreaterEqualStencilFunc = 518; + var AlwaysStencilFunc = 519; + + var StaticDrawUsage = 35044; + var DynamicDrawUsage = 35048; + var StreamDrawUsage = 35040; + var StaticReadUsage = 35045; + var DynamicReadUsage = 35049; + var StreamReadUsage = 35041; + var StaticCopyUsage = 35046; + var DynamicCopyUsage = 35050; + var StreamCopyUsage = 35042; + /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ + * https://github.com/mrdoob/eventdispatcher.js/ */ - var _Math = { + function EventDispatcher() {} - DEG2RAD: Math.PI / 180, - RAD2DEG: 180 / Math.PI, + Object.assign( EventDispatcher.prototype, { - generateUUID: ( function () { + addEventListener: function ( type, listener ) { - // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 + if ( this._listeners === undefined ) { this._listeners = {}; } - var lut = []; + var listeners = this._listeners; - for ( var i = 0; i < 256; i ++ ) { + if ( listeners[ type ] === undefined ) { - lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 ); + listeners[ type ] = []; } - return function generateUUID() { + if ( listeners[ type ].indexOf( listener ) === - 1 ) { + + listeners[ type ].push( listener ); - var d0 = Math.random() * 0xffffffff | 0; - var d1 = Math.random() * 0xffffffff | 0; - var d2 = Math.random() * 0xffffffff | 0; - var d3 = Math.random() * 0xffffffff | 0; - var 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(); + }, - }; + hasEventListener: function ( type, listener ) { + + if ( this._listeners === undefined ) { return false; } + + var listeners = this._listeners; + + return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; + + }, + + removeEventListener: function ( type, listener ) { + + if ( this._listeners === undefined ) { return; } + + var listeners = this._listeners; + var listenerArray = listeners[ type ]; + + if ( listenerArray !== undefined ) { + + var index = listenerArray.indexOf( listener ); + + if ( index !== - 1 ) { + + listenerArray.splice( index, 1 ); + + } + + } + + }, + + dispatchEvent: function ( event ) { + + if ( this._listeners === undefined ) { return; } + + var listeners = this._listeners; + var listenerArray = listeners[ event.type ]; + + if ( listenerArray !== undefined ) { + + event.target = this; + + // Make a copy, in case listeners are removed while iterating. + var array = listenerArray.slice( 0 ); + + for ( var i = 0, l = array.length; i < l; i ++ ) { + + array[ i ].call( this, event ); + + } + + } + + } + + } ); + + var _lut = []; + + for ( var i = 0; i < 256; i ++ ) { + + _lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 ); + + } + + var _seed = 1234567; + + var MathUtils = { + + DEG2RAD: Math.PI / 180, + RAD2DEG: 180 / Math.PI, + + generateUUID: function () { + + // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 - } )(), + var d0 = Math.random() * 0xffffffff | 0; + var d1 = Math.random() * 0xffffffff | 0; + var d2 = Math.random() * 0xffffffff | 0; + var d3 = Math.random() * 0xffffffff | 0; + var 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(); + + }, clamp: function ( value, min, max ) { @@ -403,8 +448,8 @@ smoothstep: function ( x, min, max ) { - if ( x <= min ) return 0; - if ( x >= max ) return 1; + if ( x <= min ) { return 0; } + if ( x >= max ) { return 1; } x = ( x - min ) / ( max - min ); @@ -414,8 +459,8 @@ smootherstep: function ( x, min, max ) { - if ( x <= min ) return 0; - if ( x >= max ) return 1; + if ( x <= min ) { return 0; } + if ( x >= max ) { return 1; } x = ( x - min ) / ( max - min ); @@ -447,15 +492,29 @@ }, + // Deterministic pseudo-random float in the interval [ 0, 1 ] + + seededRandom: function ( s ) { + + if ( s !== undefined ) { _seed = s % 2147483647; } + + // Park-Miller algorithm + + _seed = _seed * 16807 % 2147483647; + + return ( _seed - 1 ) / 2147483646; + + }, + degToRad: function ( degrees ) { - return degrees * _Math.DEG2RAD; + return degrees * MathUtils.DEG2RAD; }, radToDeg: function ( radians ) { - return radians * _Math.RAD2DEG; + return radians * MathUtils.RAD2DEG; }, @@ -475,21 +534,73 @@ return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); + }, + + setQuaternionFromProperEuler: function ( 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 + + var cos = Math.cos; + var sin = Math.sin; + + var c2 = cos( b / 2 ); + var s2 = sin( b / 2 ); + + var c13 = cos( ( a + c ) / 2 ); + var s13 = sin( ( a + c ) / 2 ); + + var c1_3 = cos( ( a - c ) / 2 ); + var s1_3 = sin( ( a - c ) / 2 ); + + var c3_1 = cos( ( c - a ) / 2 ); + var 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 ); + + } + } }; - /** - * @author mrdoob / http://mrdoob.com/ - * @author philogb / http://blog.thejit.org/ - * @author egraether / http://egraether.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - */ - function Vector2( x, y ) { + if ( x === void 0 ) x = 0; + if ( y === void 0 ) y = 0; + - this.x = x || 0; - this.y = y || 0; + this.x = x; + this.y = y; } @@ -759,21 +870,14 @@ }, - clampScalar: function () { - - var min = new Vector2(); - var max = new Vector2(); - - return function clampScalar( minVal, maxVal ) { + clampScalar: function ( minVal, maxVal ) { - min.set( minVal, minVal ); - max.set( maxVal, maxVal ); + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - return this.clamp( min, max ); - - }; + return this; - }(), + }, clampLength: function ( min, max ) { @@ -868,9 +972,7 @@ // computes the angle in radians with respect to the positive x-axis - var angle = Math.atan2( this.y, this.x ); - - if ( angle < 0 ) angle += 2 * Math.PI; + var angle = Math.atan2( - this.y, - this.x ) + Math.PI; return angle; @@ -912,7 +1014,10 @@ lerpVectors: function ( v1, v2, alpha ) { - return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + + return this; }, @@ -924,7 +1029,7 @@ fromArray: function ( array, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset === undefined ) { offset = 0; } this.x = array[ offset ]; this.y = array[ offset + 1 ]; @@ -935,8 +1040,8 @@ toArray: function ( array, offset ) { - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } array[ offset ] = this.x; array[ offset + 1 ] = this.y; @@ -972,54 +1077,48 @@ return this; + }, + + random: function () { + + this.x = Math.random(); + this.y = Math.random(); + + return this; + } } ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author philogb / http://blog.thejit.org/ - * @author jordi_ros / http://plattsoft.com - * @author D1plo1d / http://github.com/D1plo1d - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author timknip / http://www.floorplanner.com/ - * @author bhouston / http://clara.io - * @author WestLangley / http://github.com/WestLangley - */ - - function Matrix4() { + function Matrix3() { this.elements = [ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 ]; if ( arguments.length > 0 ) { - console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); + console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); } } - Object.assign( Matrix4.prototype, { + Object.assign( Matrix3.prototype, { - isMatrix4: true, + isMatrix3: true, - set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { var te = this.elements; - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; + 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; @@ -1029,10 +1128,9 @@ this.set( - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 ); @@ -1042,7 +1140,7 @@ clone: function () { - return new Matrix4().fromArray( this.elements ); + return new this.constructor().fromArray( this.elements ); }, @@ -1051,2189 +1149,2076 @@ var te = this.elements; var 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 ]; + 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; }, - copyPosition: function ( m ) { - - var te = this.elements, me = m.elements; + extractBasis: function ( xAxis, yAxis, zAxis ) { - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; + xAxis.setFromMatrix3Column( this, 0 ); + yAxis.setFromMatrix3Column( this, 1 ); + zAxis.setFromMatrix3Column( this, 2 ); return this; }, - extractBasis: function ( xAxis, yAxis, zAxis ) { - - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); + setFromMatrix4: function ( m ) { - return this; + var me = m.elements; - }, + this.set( - makeBasis: function ( xAxis, yAxis, zAxis ) { + me[ 0 ], me[ 4 ], me[ 8 ], + me[ 1 ], me[ 5 ], me[ 9 ], + me[ 2 ], me[ 6 ], me[ 10 ] - 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: function () { - - var v1 = new Vector3(); + multiply: function ( m ) { - return function extractRotation( m ) { + return this.multiplyMatrices( this, m ); - // this method does not support reflection matrices + }, - var te = this.elements; - var me = m.elements; + premultiply: function ( m ) { - var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length(); - var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length(); - var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length(); + return this.multiplyMatrices( m, this ); - 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; + multiplyMatrices: function ( a, b ) { - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; + var ae = a.elements; + var be = b.elements; + var te = this.elements; - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; + var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; + var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; - return this; + var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; + var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; + var 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; - makeRotationFromEuler: function ( euler ) { + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; + te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; + te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; - if ( ! ( euler && euler.isEuler ) ) { + return this; - console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); + }, - } + multiplyScalar: function ( s ) { var te = this.elements; - var x = euler.x, y = euler.y, z = euler.z; - var a = Math.cos( x ), b = Math.sin( x ); - var c = Math.cos( y ), d = Math.sin( y ); - var e = Math.cos( z ), f = Math.sin( z ); + 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; - if ( euler.order === 'XYZ' ) { + return this; - var ae = a * e, af = a * f, be = b * e, bf = b * f; + }, - te[ 0 ] = c * e; - te[ 4 ] = - c * f; - te[ 8 ] = d; + determinant: function () { - te[ 1 ] = af + be * d; - te[ 5 ] = ae - bf * d; - te[ 9 ] = - b * c; + var te = this.elements; - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; + var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], + d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], + g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; - } else if ( euler.order === 'YXZ' ) { + return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; - var ce = c * e, cf = c * f, de = d * e, df = d * f; + }, - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; + getInverse: function ( matrix, throwOnDegenerate ) { - te[ 1 ] = a * f; - te[ 5 ] = a * e; - te[ 9 ] = - b; + if ( throwOnDegenerate !== undefined ) { - te[ 2 ] = cf * b - de; - te[ 6 ] = df + ce * b; - te[ 10 ] = a * c; + console.warn( "THREE.Matrix3: .getInverse() can no longer be configured to throw on degenerate." ); - } else if ( euler.order === 'ZXY' ) { + } - var ce = c * e, cf = c * f, de = d * e, df = d * f; + var me = matrix.elements, + te = this.elements, - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; + n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], + n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ], + n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ], - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; + t11 = n33 * n22 - n32 * n23, + t12 = n32 * n13 - n33 * n12, + t13 = n23 * n12 - n22 * n13, - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; + det = n11 * t11 + n21 * t12 + n31 * t13; - } else if ( euler.order === 'ZYX' ) { + if ( det === 0 ) { return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); } - var ae = a * e, af = a * f, be = b * e, bf = b * f; + var detInv = 1 / det; - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; + te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; + te[ 3 ] = t12 * detInv; + te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; + te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; + te[ 6 ] = t13 * detInv; + te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; + te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; - } else if ( euler.order === 'YZX' ) { + return this; - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + }, - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; + transpose: function () { - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; + var tmp; + var m = this.elements; - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; + 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; - } else if ( euler.order === 'XZY' ) { + return this; - var ac = a * c, ad = a * d, bc = b * c, bd = b * d; + }, - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; + getNormalMatrix: function ( matrix4 ) { - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; + return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose(); - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; + }, - } + transposeIntoArray: function ( r ) { - // bottom row - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; + var m = this.elements; - // last column - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + 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; }, - makeRotationFromQuaternion: function () { + setUvTransform: function ( tx, ty, sx, sy, rotation, cx, cy ) { - var zero = new Vector3( 0, 0, 0 ); - var one = new Vector3( 1, 1, 1 ); + var c = Math.cos( rotation ); + var s = Math.sin( rotation ); - return function makeRotationFromQuaternion( q ) { + 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.compose( zero, q, one ); + }, - }; + scale: function ( sx, sy ) { - }(), + var te = this.elements; - lookAt: function () { + te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx; + te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy; - var x = new Vector3(); - var y = new Vector3(); - var z = new Vector3(); + return this; - return function lookAt( eye, target, up ) { + }, - var te = this.elements; + rotate: function ( theta ) { - z.subVectors( eye, target ); + var c = Math.cos( theta ); + var s = Math.sin( theta ); - if ( z.lengthSq() === 0 ) { + var te = this.elements; - // eye and target are in the same position + var a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ]; + var a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ]; - z.z = 1; + 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; - z.normalize(); - x.crossVectors( up, z ); + return this; - if ( x.lengthSq() === 0 ) { + }, - // up and z are parallel + translate: function ( tx, ty ) { - if ( Math.abs( up.z ) === 1 ) { + var te = this.elements; - z.x += 0.0001; + 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 ]; - } else { + return this; - z.z += 0.0001; + }, - } + equals: function ( matrix ) { - z.normalize(); - x.crossVectors( up, z ); + var te = this.elements; + var me = matrix.elements; - } + for ( var i = 0; i < 9; i ++ ) { - x.normalize(); - y.crossVectors( z, x ); + if ( te[ i ] !== me[ i ] ) { return false; } - 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; + return true; - }; + }, - }(), + fromArray: function ( array, offset ) { - multiply: function ( m, n ) { + if ( offset === undefined ) { offset = 0; } - if ( n !== undefined ) { + for ( var i = 0; i < 9; i ++ ) { - console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); - return this.multiplyMatrices( m, n ); + this.elements[ i ] = array[ i + offset ]; } - return this.multiplyMatrices( this, m ); + return this; }, - premultiply: function ( m ) { - - return this.multiplyMatrices( m, this ); - - }, + toArray: function ( array, offset ) { - multiplyMatrices: function ( a, b ) { + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } - var ae = a.elements; - var be = b.elements; var te = this.elements; - var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; - var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; + array[ offset + 3 ] = te[ 3 ]; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; - 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; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + array[ offset + 8 ] = te[ 8 ]; - 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; + return array; - 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; + var _canvas; - }, + var ImageUtils = { - multiplyScalar: function ( s ) { + getDataURL: function ( image ) { - var te = this.elements; + if ( /^data:/i.test( image.src ) ) { - 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 image.src; - return this; + } - }, + if ( typeof HTMLCanvasElement == 'undefined' ) { - applyToBufferAttribute: function () { + return image.src; - var v1 = new Vector3(); + } - return function applyToBufferAttribute( attribute ) { + var canvas; - for ( var i = 0, l = attribute.count; i < l; i ++ ) { + if ( image instanceof HTMLCanvasElement ) { - v1.x = attribute.getX( i ); - v1.y = attribute.getY( i ); - v1.z = attribute.getZ( i ); + canvas = image; - v1.applyMatrix4( this ); + } else { - attribute.setXYZ( i, v1.x, v1.y, v1.z ); + if ( _canvas === undefined ) { _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); } - } + _canvas.width = image.width; + _canvas.height = image.height; - return attribute; + var context = _canvas.getContext( '2d' ); - }; + if ( image instanceof ImageData ) { - }(), + context.putImageData( image, 0, 0 ); - determinant: function () { + } else { - var te = this.elements; + context.drawImage( image, 0, 0, image.width, image.height ); - var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; + } - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) + canvas = _canvas; - 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 - ) + } - ); + if ( canvas.width > 2048 || canvas.height > 2048 ) { - }, + return canvas.toDataURL( 'image/jpeg', 0.6 ); - transpose: function () { + } else { - var te = this.elements; - var tmp; + return canvas.toDataURL( 'image/png' ); - 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; + }; - }, + var textureId = 0; - setPosition: function ( v ) { + function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { - var te = this.elements; + Object.defineProperty( this, 'id', { value: textureId ++ } ); - te[ 12 ] = v.x; - te[ 13 ] = v.y; - te[ 14 ] = v.z; + this.uuid = MathUtils.generateUUID(); - return this; + this.name = ''; - }, + this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE; + this.mipmaps = []; - getInverse: function ( m, throwOnDegenerate ) { + this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING; - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - var te = this.elements, - me = m.elements, + this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping; + this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping; - n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ], - n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ], - n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ], - n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ], + this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; + this.minFilter = minFilter !== undefined ? minFilter : LinearMipmapLinearFilter; - 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; + this.anisotropy = anisotropy !== undefined ? anisotropy : 1; - var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; + this.format = format !== undefined ? format : RGBAFormat; + this.internalFormat = null; + this.type = type !== undefined ? type : UnsignedByteType; - if ( det === 0 ) { + this.offset = new Vector2( 0, 0 ); + this.repeat = new Vector2( 1, 1 ); + this.center = new Vector2( 0, 0 ); + this.rotation = 0; - var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0"; + this.matrixAutoUpdate = true; + this.matrix = new Matrix3(); - if ( throwOnDegenerate === true ) { + 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) - throw new Error( msg ); + // 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 !== undefined ? encoding : LinearEncoding; - } else { + this.version = 0; + this.onUpdate = null; - console.warn( msg ); + } - } + Texture.DEFAULT_IMAGE = undefined; + Texture.DEFAULT_MAPPING = UVMapping; - return this.identity(); + Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - } + constructor: Texture, - var detInv = 1 / det; + isTexture: true, - 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; + updateMatrix: function () { - 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; + this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); - 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; + clone: function () { - return this; + return new this.constructor().copy( this ); }, - scale: function ( v ) { + copy: function ( source ) { - var te = this.elements; - var x = v.x, y = v.y, z = v.z; + this.name = source.name; - 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; + this.image = source.image; + this.mipmaps = source.mipmaps.slice( 0 ); - return this; + this.mapping = source.mapping; - }, + this.wrapS = source.wrapS; + this.wrapT = source.wrapT; - getMaxScaleOnAxis: function () { + this.magFilter = source.magFilter; + this.minFilter = source.minFilter; - var te = this.elements; + this.anisotropy = source.anisotropy; - var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + this.format = source.format; + this.internalFormat = source.internalFormat; + this.type = source.type; - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); + 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 ); - makeTranslation: function ( x, y, z ) { + this.generateMipmaps = source.generateMipmaps; + this.premultiplyAlpha = source.premultiplyAlpha; + this.flipY = source.flipY; + this.unpackAlignment = source.unpackAlignment; + this.encoding = source.encoding; - this.set( + return this; - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 + }, - ); + toJSON: function ( meta ) { - return this; + var isRootObject = ( meta === undefined || typeof meta === 'string' ); - }, + if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { - makeRotationX: function ( theta ) { + return meta.textures[ this.uuid ]; - var c = Math.cos( theta ), s = Math.sin( theta ); + } - this.set( + var output = { - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 + metadata: { + version: 4.5, + type: 'Texture', + generator: 'Texture.toJSON' + }, - ); + uuid: this.uuid, + name: this.name, - return this; + 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, - makeRotationY: function ( theta ) { + wrap: [ this.wrapS, this.wrapT ], - var c = Math.cos( theta ), s = Math.sin( theta ); + format: this.format, + type: this.type, + encoding: this.encoding, - this.set( + minFilter: this.minFilter, + magFilter: this.magFilter, + anisotropy: this.anisotropy, - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 + flipY: this.flipY, - ); + premultiplyAlpha: this.premultiplyAlpha, + unpackAlignment: this.unpackAlignment - return this; + }; - }, + if ( this.image !== undefined ) { - makeRotationZ: function ( theta ) { + // TODO: Move to THREE.Image - var c = Math.cos( theta ), s = Math.sin( theta ); + var image = this.image; - this.set( + if ( image.uuid === undefined ) { - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + image.uuid = MathUtils.generateUUID(); // UGH - ); + } - return this; + if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) { - }, + var url; - makeRotationAxis: function ( axis, angle ) { + if ( Array.isArray( image ) ) { - // Based on http://www.gamedev.net/reference/articles/article1199.asp + // process array of images e.g. CubeTexture - var c = Math.cos( angle ); - var s = Math.sin( angle ); - var t = 1 - c; - var x = axis.x, y = axis.y, z = axis.z; - var tx = t * x, ty = t * y; + url = []; - this.set( + for ( var i = 0, l = image.length; i < l; i ++ ) { - 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 + url.push( ImageUtils.getDataURL( image[ i ] ) ); - ); + } - return this; + } else { - }, + // process single image - makeScale: function ( x, y, z ) { + url = ImageUtils.getDataURL( image ); - this.set( + } - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 + meta.images[ image.uuid ] = { + uuid: image.uuid, + url: url + }; - ); + } - return this; + output.image = image.uuid; - }, + } - makeShear: function ( x, y, z ) { + if ( ! isRootObject ) { - this.set( + meta.textures[ this.uuid ] = output; - 1, y, z, 0, - x, 1, z, 0, - x, y, 1, 0, - 0, 0, 0, 1 + } - ); + return output; - return this; + }, + + dispose: function () { + + this.dispatchEvent( { type: 'dispose' } ); }, - compose: function ( position, quaternion, scale ) { + transformUv: function ( uv ) { - var te = this.elements; + if ( this.mapping !== UVMapping ) { return uv; } - var x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; - var x2 = x + x, y2 = y + y, z2 = z + z; - var xx = x * x2, xy = x * y2, xz = x * z2; - var yy = y * y2, yz = y * z2, zz = z * z2; - var wx = w * x2, wy = w * y2, wz = w * z2; + uv.applyMatrix3( this.matrix ); - var sx = scale.x, sy = scale.y, sz = scale.z; + if ( uv.x < 0 || uv.x > 1 ) { - te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; - te[ 1 ] = ( xy + wz ) * sx; - te[ 2 ] = ( xz - wy ) * sx; - te[ 3 ] = 0; + switch ( this.wrapS ) { - te[ 4 ] = ( xy - wz ) * sy; - te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; - te[ 6 ] = ( yz + wx ) * sy; - te[ 7 ] = 0; + case RepeatWrapping: - te[ 8 ] = ( xz + wy ) * sz; - te[ 9 ] = ( yz - wx ) * sz; - te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; - te[ 11 ] = 0; + uv.x = uv.x - Math.floor( uv.x ); + break; - te[ 12 ] = position.x; - te[ 13 ] = position.y; - te[ 14 ] = position.z; - te[ 15 ] = 1; + case ClampToEdgeWrapping: - return this; + uv.x = uv.x < 0 ? 0 : 1; + break; - }, + case MirroredRepeatWrapping: - decompose: function () { + if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - var vector = new Vector3(); - var matrix = new Matrix4(); + uv.x = Math.ceil( uv.x ) - uv.x; - return function decompose( position, quaternion, scale ) { + } else { - var te = this.elements; + uv.x = uv.x - Math.floor( uv.x ); - var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); - var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); - var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + } - // if determine is negative, we need to invert one scale - var det = this.determinant(); - if ( det < 0 ) sx = - sx; + break; - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; + } - // scale the rotation part - matrix.copy( this ); + } - var invSX = 1 / sx; - var invSY = 1 / sy; - var invSZ = 1 / sz; + if ( uv.y < 0 || uv.y > 1 ) { - matrix.elements[ 0 ] *= invSX; - matrix.elements[ 1 ] *= invSX; - matrix.elements[ 2 ] *= invSX; + switch ( this.wrapT ) { - matrix.elements[ 4 ] *= invSY; - matrix.elements[ 5 ] *= invSY; - matrix.elements[ 6 ] *= invSY; + case RepeatWrapping: - matrix.elements[ 8 ] *= invSZ; - matrix.elements[ 9 ] *= invSZ; - matrix.elements[ 10 ] *= invSZ; + uv.y = uv.y - Math.floor( uv.y ); + break; - quaternion.setFromRotationMatrix( matrix ); + case ClampToEdgeWrapping: - scale.x = sx; - scale.y = sy; - scale.z = sz; + uv.y = uv.y < 0 ? 0 : 1; + break; - return this; + case MirroredRepeatWrapping: - }; + if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - }(), + uv.y = Math.ceil( uv.y ) - uv.y; - makePerspective: function ( left, right, top, bottom, near, far ) { + } else { - if ( far === undefined ) { + uv.y = uv.y - Math.floor( uv.y ); - console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' ); + } + + break; + + } } - var te = this.elements; - var x = 2 * near / ( right - left ); - var y = 2 * near / ( top - bottom ); + if ( this.flipY ) { - var a = ( right + left ) / ( right - left ); - var b = ( top + bottom ) / ( top - bottom ); - var c = - ( far + near ) / ( far - near ); - var d = - 2 * far * near / ( far - near ); + uv.y = 1 - uv.y; - 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; + return uv; - }, + } - makeOrthographic: function ( left, right, top, bottom, near, far ) { + } ); - var te = this.elements; - var w = 1.0 / ( right - left ); - var h = 1.0 / ( top - bottom ); - var p = 1.0 / ( far - near ); + Object.defineProperty( Texture.prototype, "needsUpdate", { - var x = ( right + left ) * w; - var y = ( top + bottom ) * h; - var z = ( far + near ) * p; + set: function ( value ) { - 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; + if ( value === true ) { this.version ++; } - return this; + } - }, + } ); - equals: function ( matrix ) { + function Vector4( x, y, z, w ) { + if ( x === void 0 ) x = 0; + if ( y === void 0 ) y = 0; + if ( z === void 0 ) z = 0; + if ( w === void 0 ) w = 1; - var te = this.elements; - var me = matrix.elements; - for ( var i = 0; i < 16; i ++ ) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; - if ( te[ i ] !== me[ i ] ) return false; + } - } + Object.defineProperties( Vector4.prototype, { - return true; + "width": { - }, + get: function () { - fromArray: function ( array, offset ) { + return this.z; - if ( offset === undefined ) offset = 0; + }, - for ( var i = 0; i < 16; i ++ ) { + set: function ( value ) { - this.elements[ i ] = array[ i + offset ]; + this.z = value; } - return this; - }, - toArray: function ( array, offset ) { + "height": { - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; + get: function () { - var te = this.elements; + return this.w; - 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 ]; + set: function ( value ) { - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; + this.w = value; - return array; + } } } ); - /** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://clara.io - */ - - function Quaternion( x, y, z, w ) { - - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._w = ( w !== undefined ) ? w : 1; + Object.assign( Vector4.prototype, { - } + isVector4: true, - Object.assign( Quaternion, { + set: function ( x, y, z, w ) { - slerp: function ( qa, qb, qm, t ) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; - return qm.copy( qa ).slerp( qb, t ); + return this; }, - slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { + setScalar: function ( scalar ) { - // fuzz-free, array-based Quaternion SLERP operation + this.x = scalar; + this.y = scalar; + this.z = scalar; + this.w = scalar; - var x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ], + return this; - x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; + }, - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + setX: function ( x ) { - var s = 1 - t, + this.x = x; - cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + return this; - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; + }, - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { + setY: function ( y ) { - var sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); + this.y = y; - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; + return this; - } + }, - var tDir = t * dir; + setZ: function ( z ) { - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; + this.z = z; - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { + return this; - var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + }, - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; + setW: function ( w ) { - } + this.w = w; - } + return this; - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; + }, - } + setComponent: function ( index, value ) { - } ); + switch ( index ) { - Object.defineProperties( Quaternion.prototype, { + 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 ); - x: { + } - get: function () { + return this; - return this._x; + }, - }, + getComponent: function ( index ) { - set: function ( value ) { + switch ( index ) { - this._x = value; - this.onChangeCallback(); + 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 ); } }, - y: { - - get: function () { + clone: function () { - return this._y; + return new this.constructor( this.x, this.y, this.z, this.w ); - }, + }, - set: function ( value ) { + copy: function ( v ) { - this._y = value; - this.onChangeCallback(); + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; - } + return this; }, - z: { - - get: function () { - - return this._z; - - }, + add: function ( v, w ) { - set: function ( value ) { + if ( w !== undefined ) { - this._z = value; - this.onChangeCallback(); + console.warn( 'THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); } - }, - - w: { - - get: function () { + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; - return this._w; + return this; - }, + }, - set: function ( value ) { + addScalar: function ( s ) { - this._w = value; - this.onChangeCallback(); + this.x += s; + this.y += s; + this.z += s; + this.w += s; - } + return this; - } + }, - } ); + addVectors: function ( a, b ) { - Object.assign( Quaternion.prototype, { + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; - isQuaternion: true, + return this; - set: function ( x, y, z, w ) { + }, - this._x = x; - this._y = y; - this._z = z; - this._w = w; + addScaledVector: function ( v, s ) { - this.onChangeCallback(); + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + this.w += v.w * s; return this; }, - clone: function () { - - return new this.constructor( this._x, this._y, this._z, this._w ); + sub: function ( v, w ) { - }, + if ( w !== undefined ) { - copy: function ( quaternion ) { + console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; + } - this.onChangeCallback(); + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; return this; }, - setFromEuler: function ( euler, update ) { - - if ( ! ( euler && euler.isEuler ) ) { + subScalar: function ( s ) { - throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' ); + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; - } + return this; - var 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 + subVectors: function ( a, b ) { - var cos = Math.cos; - var sin = Math.sin; + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; - var c1 = cos( x / 2 ); - var c2 = cos( y / 2 ); - var c3 = cos( z / 2 ); + return this; - var s1 = sin( x / 2 ); - var s2 = sin( y / 2 ); - var s3 = sin( z / 2 ); + }, - if ( order === 'XYZ' ) { + multiplyScalar: function ( scalar ) { - 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; + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; - } else if ( order === 'YXZ' ) { + return this; - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 - s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 + s1 * s2 * s3; + }, - } else if ( order === 'ZXY' ) { + applyMatrix4: function ( m ) { - 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; + var x = this.x, y = this.y, z = this.z, w = this.w; + var e = m.elements; - } else if ( order === 'ZYX' ) { + 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; - 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; + return this; - } else if ( order === 'YZX' ) { + }, - this._x = s1 * c2 * c3 + c1 * s2 * s3; - this._y = c1 * s2 * c3 + s1 * c2 * s3; - this._z = c1 * c2 * s3 - s1 * s2 * c3; - this._w = c1 * c2 * c3 - s1 * s2 * s3; + divideScalar: function ( scalar ) { - } else if ( order === 'XZY' ) { + return this.multiplyScalar( 1 / scalar ); - 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; + }, - } + setAxisAngleFromQuaternion: function ( q ) { - if ( update !== false ) this.onChangeCallback(); + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - return this; + // q is assumed to be normalized - }, + this.w = 2 * Math.acos( q.w ); - setFromAxisAngle: function ( axis, angle ) { + var s = Math.sqrt( 1 - q.w * q.w ); - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + if ( s < 0.0001 ) { - // assumes axis is normalized + this.x = 1; + this.y = 0; + this.z = 0; - var halfAngle = angle / 2, s = Math.sin( halfAngle ); + } else { - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; - this.onChangeCallback(); + } return this; }, - setFromRotationMatrix: function ( m ) { + setAxisAngleFromRotationMatrix: function ( m ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - var te = m.elements, + var angle, x, y, z; // variables for result + var 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 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - trace = m11 + m22 + m33, - s; + if ( ( Math.abs( m12 - m21 ) < epsilon ) && + ( Math.abs( m13 - m31 ) < epsilon ) && + ( Math.abs( m23 - m32 ) < epsilon ) ) { - if ( trace > 0 ) { + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms - s = 0.5 / Math.sqrt( trace + 1.0 ); + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && + ( Math.abs( m13 + m31 ) < epsilon2 ) && + ( Math.abs( m23 + m32 ) < epsilon2 ) && + ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; + // this singularity is identity matrix so angle = 0 - } else if ( m11 > m22 && m11 > m33 ) { + this.set( 1, 0, 0, 0 ); - s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + return this; // zero angle, arbitrary axis - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; + } - } else if ( m22 > m33 ) { + // otherwise this singularity is angle = 180 - s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + angle = Math.PI; - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; + var xx = ( m11 + 1 ) / 2; + var yy = ( m22 + 1 ) / 2; + var zz = ( m33 + 1 ) / 2; + var xy = ( m12 + m21 ) / 4; + var xz = ( m13 + m31 ) / 4; + var yz = ( m23 + m32 ) / 4; - } else { + if ( ( xx > yy ) && ( xx > zz ) ) { - s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + // m11 is the largest diagonal term - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; + if ( xx < epsilon ) { - } + x = 0; + y = 0.707106781; + z = 0.707106781; - this.onChangeCallback(); + } else { - return this; + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; - }, + } - setFromUnitVectors: function () { + } else if ( yy > zz ) { - // assumes direction vectors vFrom and vTo are normalized + // m22 is the largest diagonal term - var v1 = new Vector3(); - var r; + if ( yy < epsilon ) { - var EPS = 0.000001; + x = 0.707106781; + y = 0; + z = 0.707106781; - return function setFromUnitVectors( vFrom, vTo ) { + } else { - if ( v1 === undefined ) v1 = new Vector3(); + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; - r = vFrom.dot( vTo ) + 1; + } - if ( r < EPS ) { + } else { - r = 0; + // m33 is the largest diagonal term so base result on this - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + if ( zz < epsilon ) { - v1.set( - vFrom.y, vFrom.x, 0 ); + x = 0.707106781; + y = 0.707106781; + z = 0; } else { - v1.set( 0, - vFrom.z, vFrom.y ); + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; } - } else { - - v1.crossVectors( vFrom, vTo ); - } - this._x = v1.x; - this._y = v1.y; - this._z = v1.z; - this._w = r; + this.set( x, y, z, angle ); - return this.normalize(); + return this; // return 180 deg rotation - }; + } - }(), + // as we have reached here there are no singularities so we can handle normally - angleTo: function ( q ) { + var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - return 2 * Math.acos( Math.abs( _Math.clamp( this.dot( q ), - 1, 1 ) ) ); + 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 - rotateTowards: function ( q, step ) { + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - var angle = this.angleTo( q ); + return this; - if ( angle === 0 ) return this; + }, - var t = Math.min( 1, step / angle ); + min: function ( v ) { - this.slerp( q, t ); + 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; }, - inverse: function () { + max: function ( v ) { - // quaternion is assumed to have unit length + 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.conjugate(); + return this; }, - conjugate: function () { + clamp: function ( min, max ) { - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; + // assumes min < max, componentwise - this.onChangeCallback(); + 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; }, - dot: function ( v ) { + clampScalar: function ( minVal, maxVal ) { - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + 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; }, - lengthSq: function () { + clampLength: function ( min, max ) { - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + var length = this.length(); + + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); }, - length: function () { + floor: function () { - return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); + + return this; }, - normalize: function () { + ceil: function () { - var l = this.length(); + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); - if ( l === 0 ) { + return this; - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; + }, - } else { + round: function () { - l = 1 / l; + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; + return this; - } + }, + + roundToZero: function () { - this.onChangeCallback(); + 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; }, - multiply: function ( q, p ) { + negate: function () { - if ( p !== undefined ) { + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; - console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); - return this.multiplyQuaternions( q, p ); + return this; - } + }, - return this.multiplyQuaternions( this, q ); + dot: function ( v ) { + + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; }, - premultiply: function ( q ) { + lengthSq: function () { - return this.multiplyQuaternions( q, this ); + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; }, - multiplyQuaternions: function ( a, b ) { - - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + length: function () { - var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.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(); + manhattanLength: function () { - return this; + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); }, - slerp: function ( qb, t ) { + normalize: function () { - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); + return this.divideScalar( this.length() || 1 ); - var x = this._x, y = this._y, z = this._z, w = this._w; + }, - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + setLength: function ( length ) { - var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + return this.normalize().multiplyScalar( length ); - 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 ); + lerp: function ( v, alpha ) { - } + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; - if ( cosHalfTheta >= 1.0 ) { + return this; - this._w = w; - this._x = x; - this._y = y; - this._z = z; + }, - return this; + lerpVectors: function ( 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; - var sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; + return this; - if ( sqrSinHalfTheta <= Number.EPSILON ) { + }, - var 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; + equals: function ( v ) { - return this.normalize(); + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); - } + }, - var sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); - var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + fromArray: function ( array, offset ) { - 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 ); + if ( offset === undefined ) { offset = 0; } - this.onChangeCallback(); + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; return this; }, - equals: function ( quaternion ) { + toArray: function ( array, offset ) { - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } + + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + array[ offset + 3 ] = this.w; + + return array; }, - fromArray: function ( array, offset ) { + fromBufferAttribute: function ( attribute, index, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset !== undefined ) { - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; + console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' ); - this.onChangeCallback(); + } + + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + this.w = attribute.getW( index ); return this; }, - toArray: function ( array, offset ) { + random: function () { - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + this.w = Math.random(); - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; + return this; - return array; + } - }, + } ); - onChange: function ( callback ) { + /* + In options, we can specify: + * Texture parameters for an auto-generated target texture + * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers + */ + function WebGLRenderTarget( width, height, options ) { - this.onChangeCallback = callback; + this.width = width; + this.height = height; - return this; + this.scissor = new Vector4( 0, 0, width, height ); + this.scissorTest = false; - }, + this.viewport = new Vector4( 0, 0, width, height ); - onChangeCallback: function () {} + options = options || {}; - } ); + this.texture = new Texture( undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author kile / http://kile.stravaganza.org/ - * @author philogb / http://blog.thejit.org/ - * @author mikael emtinger / http://gomo.se/ - * @author egraether / http://egraether.com/ - * @author WestLangley / http://github.com/WestLangley - */ + this.texture.image = {}; + this.texture.image.width = width; + this.texture.image.height = height; - function Vector3( x, y, z ) { + this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; + this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; + this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; + this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; + this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; } - Object.assign( Vector3.prototype, { + WebGLRenderTarget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - isVector3: true, + constructor: WebGLRenderTarget, - set: function ( x, y, z ) { + isWebGLRenderTarget: true, - this.x = x; - this.y = y; - this.z = z; + setSize: function ( width, height ) { - return this; + if ( this.width !== width || this.height !== height ) { - }, + this.width = width; + this.height = height; - setScalar: function ( scalar ) { + this.texture.image.width = width; + this.texture.image.height = height; - this.x = scalar; - this.y = scalar; - this.z = scalar; + this.dispose(); - return this; + } - }, + this.viewport.set( 0, 0, width, height ); + this.scissor.set( 0, 0, width, height ); - setX: function ( x ) { + }, - this.x = x; + clone: function () { - return this; + return new this.constructor().copy( this ); }, - setY: function ( y ) { - - this.y = y; + copy: function ( source ) { - return this; + this.width = source.width; + this.height = source.height; - }, + this.viewport.copy( source.viewport ); - setZ: function ( z ) { + this.texture = source.texture.clone(); - this.z = z; + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; + this.depthTexture = source.depthTexture; return this; }, - setComponent: function ( index, value ) { + dispose: function () { - switch ( index ) { + this.dispatchEvent( { type: 'dispose' } ); - 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; + function WebGLMultisampleRenderTarget( width, height, options ) { - }, + WebGLRenderTarget.call( this, width, height, options ); - getComponent: function ( index ) { + this.samples = 4; - 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 ); + WebGLMultisampleRenderTarget.prototype = Object.assign( Object.create( WebGLRenderTarget.prototype ), { - } + constructor: WebGLMultisampleRenderTarget, - }, + isWebGLMultisampleRenderTarget: true, - clone: function () { + copy: function ( source ) { - return new this.constructor( this.x, this.y, this.z ); + WebGLRenderTarget.prototype.copy.call( this, source ); - }, + this.samples = source.samples; - copy: function ( v ) { + return this; - this.x = v.x; - this.y = v.y; - this.z = v.z; + } - return this; + } ); - }, + function Quaternion( x, y, z, w ) { + if ( x === void 0 ) x = 0; + if ( y === void 0 ) y = 0; + if ( z === void 0 ) z = 0; + if ( w === void 0 ) w = 1; - add: function ( v, w ) { - if ( w !== undefined ) { + this._x = x; + this._y = y; + this._z = z; + this._w = w; - console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); - return this.addVectors( v, w ); + } - } + Object.assign( Quaternion, { - this.x += v.x; - this.y += v.y; - this.z += v.z; + slerp: function ( qa, qb, qm, t ) { - return this; + return qm.copy( qa ).slerp( qb, t ); }, - addScalar: function ( s ) { + slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - this.x += s; - this.y += s; - this.z += s; + // fuzz-free, array-based Quaternion SLERP operation - return this; + var x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ]; - }, + var x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; - addVectors: function ( a, b ) { + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; + var s = 1 - t, - return this; + cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - }, + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; - addScaledVector: function ( v, s ) { + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; + var sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); - return this; + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; - }, + } - sub: function ( v, w ) { + var tDir = t * dir; - if ( w !== undefined ) { + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; - console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { - } + var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; - return this; + } + + } + + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; }, - subScalar: function ( s ) { + multiplyQuaternionsFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - this.x -= s; - this.y -= s; - this.z -= s; + var x0 = src0[ srcOffset0 ]; + var y0 = src0[ srcOffset0 + 1 ]; + var z0 = src0[ srcOffset0 + 2 ]; + var w0 = src0[ srcOffset0 + 3 ]; - return this; + var x1 = src1[ srcOffset1 ]; + var y1 = src1[ srcOffset1 + 1 ]; + var z1 = src1[ srcOffset1 + 2 ]; + var 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; - subVectors: function ( a, b ) { + return dst; - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; + } - return this; + } ); - }, + Object.defineProperties( Quaternion.prototype, { - multiply: function ( v, w ) { + x: { - if ( w !== undefined ) { + get: function () { - console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); - return this.multiplyVectors( v, w ); + return this._x; - } + }, - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; + set: function ( value ) { - return this; + this._x = value; + this._onChangeCallback(); + + } }, - multiplyScalar: function ( scalar ) { + y: { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; + get: function () { - return this; + return this._y; - }, + }, - multiplyVectors: function ( a, b ) { + set: function ( value ) { - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; + this._y = value; + this._onChangeCallback(); - return this; + } }, - applyEuler: function () { - - var quaternion = new Quaternion(); - - return function applyEuler( euler ) { + z: { - if ( ! ( euler && euler.isEuler ) ) { + get: function () { - console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' ); + return this._z; - } + }, - return this.applyQuaternion( quaternion.setFromEuler( euler ) ); + set: function ( value ) { - }; + this._z = value; + this._onChangeCallback(); - }(), + } - applyAxisAngle: function () { + }, - var quaternion = new Quaternion(); + w: { - return function applyAxisAngle( axis, angle ) { + get: function () { - return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); + return this._w; - }; + }, - }(), + set: function ( value ) { - applyMatrix3: function ( m ) { + this._w = value; + this._onChangeCallback(); - var x = this.x, y = this.y, z = this.z; - var e = m.elements; + } - this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; - this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; - this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; + } - return this; + } ); - }, + Object.assign( Quaternion.prototype, { - applyMatrix4: function ( m ) { + isQuaternion: true, - var x = this.x, y = this.y, z = this.z; - var e = m.elements; + set: function ( x, y, z, w ) { - var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); + this._x = x; + this._y = y; + this._z = z; + this._w = w; - 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._onChangeCallback(); return this; }, - applyQuaternion: function ( q ) { + clone: function () { - var x = this.x, y = this.y, z = this.z; - var qx = q.x, qy = q.y, qz = q.z, qw = q.w; + return new this.constructor( this._x, this._y, this._z, this._w ); - // calculate quat * vector + }, - var ix = qw * x + qy * z - qz * y; - var iy = qw * y + qz * x - qx * z; - var iz = qw * z + qx * y - qy * x; - var iw = - qx * x - qy * y - qz * z; + copy: function ( quaternion ) { - // calculate result * inverse quat + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; - 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; + this._onChangeCallback(); return this; }, - project: function ( camera ) { - - return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); + setFromEuler: function ( euler, update ) { - }, + if ( ! ( euler && euler.isEuler ) ) { - unproject: function () { + throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' ); - var matrix = new Matrix4(); + } - return function unproject( camera ) { + var x = euler._x, y = euler._y, z = euler._z, order = euler.order; - return this.applyMatrix4( matrix.getInverse( camera.projectionMatrix ) ).applyMatrix4( camera.matrixWorld ); + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m - }; + var cos = Math.cos; + var sin = Math.sin; - }(), + var c1 = cos( x / 2 ); + var c2 = cos( y / 2 ); + var c3 = cos( z / 2 ); - transformDirection: function ( m ) { + var s1 = sin( x / 2 ); + var s2 = sin( y / 2 ); + var s3 = sin( z / 2 ); - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction + switch ( order ) { - var x = this.x, y = this.y, z = this.z; - var e = m.elements; + 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; - 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; + 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; - return this.normalize(); + 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; - divide: function ( v ) { + 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; - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; + 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; - return this; + default: + console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); - }, + } - divideScalar: function ( scalar ) { + if ( update !== false ) { this._onChangeCallback(); } - return this.multiplyScalar( 1 / scalar ); + return this; }, - min: function ( v ) { + setFromAxisAngle: function ( axis, angle ) { - this.x = Math.min( this.x, v.x ); - this.y = Math.min( this.y, v.y ); - this.z = Math.min( this.z, v.z ); + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - return this; + // assumes axis is normalized - }, + var halfAngle = angle / 2, s = Math.sin( halfAngle ); - max: function ( v ) { + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); - 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._onChangeCallback(); return this; }, - clamp: function ( 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 ) ); + setFromRotationMatrix: function ( m ) { - return this; + // 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) - clampScalar: function () { + var te = m.elements, - var min = new Vector3(); - var max = new Vector3(); + 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 ], - return function clampScalar( minVal, maxVal ) { + trace = m11 + m22 + m33; - min.set( minVal, minVal, minVal ); - max.set( maxVal, maxVal, maxVal ); + if ( trace > 0 ) { - return this.clamp( min, max ); + var 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 ) { - clampLength: function ( min, max ) { + var s$1 = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - var length = this.length(); + this._w = ( m32 - m23 ) / s$1; + this._x = 0.25 * s$1; + this._y = ( m12 + m21 ) / s$1; + this._z = ( m13 + m31 ) / s$1; - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + } else if ( m22 > m33 ) { - }, + var s$2 = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - floor: function () { + this._w = ( m13 - m31 ) / s$2; + this._x = ( m12 + m21 ) / s$2; + this._y = 0.25 * s$2; + this._z = ( m23 + m32 ) / s$2; - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); + } else { - return this; + var s$3 = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - }, + this._w = ( m21 - m12 ) / s$3; + this._x = ( m13 + m31 ) / s$3; + this._y = ( m23 + m32 ) / s$3; + this._z = 0.25 * s$3; - ceil: function () { + } - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); + this._onChangeCallback(); return this; }, - round: function () { + setFromUnitVectors: function ( vFrom, vTo ) { - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); + // assumes direction vectors vFrom and vTo are normalized - return this; + var EPS = 0.000001; - }, + var r = vFrom.dot( vTo ) + 1; - roundToZero: function () { + if ( r < EPS ) { - 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 ); + r = 0; - return this; + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - }, + this._x = - vFrom.y; + this._y = vFrom.x; + this._z = 0; + this._w = r; - negate: function () { + } else { - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; + this._x = 0; + this._y = - vFrom.z; + this._z = vFrom.y; + this._w = r; - return this; + } - }, - - dot: function ( v ) { - - return this.x * v.x + this.y * v.y + this.z * v.z; + } else { - }, + // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 - // TODO lengthSquared? + 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; - lengthSq: function () { + } - return this.x * this.x + this.y * this.y + this.z * this.z; + return this.normalize(); }, - length: function () { + angleTo: function ( q ) { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + return 2 * Math.acos( Math.abs( MathUtils.clamp( this.dot( q ), - 1, 1 ) ) ); }, - manhattanLength: function () { + rotateTowards: function ( q, step ) { - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); + var angle = this.angleTo( q ); - }, + if ( angle === 0 ) { return this; } - normalize: function () { + var t = Math.min( 1, step / angle ); - return this.divideScalar( this.length() || 1 ); + this.slerp( q, t ); + + return this; }, - setLength: function ( length ) { + identity: function () { - return this.normalize().multiplyScalar( length ); + return this.set( 0, 0, 0, 1 ); }, - lerp: function ( v, alpha ) { + inverse: function () { - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; + // quaternion is assumed to have unit length - return this; + return this.conjugate(); }, - lerpVectors: function ( v1, v2, alpha ) { - - return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + conjugate: function () { - }, + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; - cross: function ( v, w ) { + this._onChangeCallback(); - if ( w !== undefined ) { + return this; - console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); - return this.crossVectors( v, w ); + }, - } + dot: function ( v ) { - return this.crossVectors( this, v ); + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; }, - crossVectors: function ( a, b ) { - - var ax = a.x, ay = a.y, az = a.z; - var bx = b.x, by = b.y, bz = b.z; - - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + lengthSq: function () { - return this; + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; }, - projectOnVector: function ( vector ) { - - var scalar = vector.dot( this ) / vector.lengthSq(); + length: function () { - return this.copy( vector ).multiplyScalar( scalar ); + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); }, - projectOnPlane: function () { - - var v1 = new Vector3(); - - return function projectOnPlane( planeNormal ) { + normalize: function () { - v1.copy( this ).projectOnVector( planeNormal ); + var l = this.length(); - return this.sub( v1 ); + if ( l === 0 ) { - }; + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; - }(), + } else { - reflect: function () { + l = 1 / l; - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; - var v1 = new Vector3(); + } - return function reflect( normal ) { + this._onChangeCallback(); - return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + return this; - }; + }, - }(), + multiply: function ( q, p ) { - angleTo: function ( v ) { + if ( p !== undefined ) { - var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) ); + console.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); + return this.multiplyQuaternions( q, p ); - // clamp, to handle numerical problems + } - return Math.acos( _Math.clamp( theta, - 1, 1 ) ); + return this.multiplyQuaternions( this, q ); }, - distanceTo: function ( v ) { + premultiply: function ( q ) { - return Math.sqrt( this.distanceToSquared( v ) ); + return this.multiplyQuaternions( q, this ); }, - distanceToSquared: function ( v ) { + multiplyQuaternions: function ( a, b ) { - var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - return dx * dx + dy * dy + dz * dz; + var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - }, + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - manhattanDistanceTo: function ( v ) { + this._onChangeCallback(); - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); + return this; }, - setFromSpherical: function ( s ) { - - return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); - - }, + slerp: function ( qb, t ) { - setFromSphericalCoords: function ( radius, phi, theta ) { + if ( t === 0 ) { return this; } + if ( t === 1 ) { return this.copy( qb ); } - var sinPhiRadius = Math.sin( phi ) * radius; + var x = this._x, y = this._y, z = this._z, w = this._w; - this.x = sinPhiRadius * Math.sin( theta ); - this.y = Math.cos( phi ) * radius; - this.z = sinPhiRadius * Math.cos( theta ); + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - return this; + var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - }, + if ( cosHalfTheta < 0 ) { - setFromCylindrical: function ( c ) { + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; - return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); + cosHalfTheta = - cosHalfTheta; - }, + } else { - setFromCylindricalCoords: function ( radius, theta, y ) { + this.copy( qb ); - this.x = radius * Math.sin( theta ); - this.y = y; - this.z = radius * Math.cos( theta ); + } - return this; + if ( cosHalfTheta >= 1.0 ) { - }, + this._w = w; + this._x = x; + this._y = y; + this._z = z; - setFromMatrixPosition: function ( m ) { + return this; - var e = m.elements; + } - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; + var sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - return this; + if ( sqrSinHalfTheta <= Number.EPSILON ) { - }, + var 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; - setFromMatrixScale: function ( m ) { + this.normalize(); + this._onChangeCallback(); - var sx = this.setFromMatrixColumn( m, 0 ).length(); - var sy = this.setFromMatrixColumn( m, 1 ).length(); - var sz = this.setFromMatrixColumn( m, 2 ).length(); + return this; - this.x = sx; - this.y = sy; - this.z = sz; + } - return this; + var sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); + var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); + var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - }, + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); - setFromMatrixColumn: function ( m, index ) { + this._onChangeCallback(); - return this.fromArray( m.elements, index * 4 ); + return this; }, - equals: function ( v ) { + equals: function ( quaternion ) { - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); }, fromArray: function ( array, offset ) { - if ( offset === undefined ) offset = 0; + if ( offset === undefined ) { offset = 0; } - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; + + this._onChangeCallback(); return this; @@ -3241,5561 +3226,5531 @@ toArray: function ( array, offset ) { - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; return array; }, - fromBufferAttribute: function ( attribute, index, offset ) { + fromBufferAttribute: function ( attribute, index ) { - if ( offset !== undefined ) { + this._x = attribute.getX( index ); + this._y = attribute.getY( index ); + this._z = attribute.getZ( index ); + this._w = attribute.getW( index ); - console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' ); + return this; - } + }, - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); + _onChange: function ( callback ) { + + this._onChangeCallback = callback; return this; - } + }, + + _onChangeCallback: function () {} } ); - /** - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://clara.io - * @author tschw - */ + var _vector = new Vector3(); + var _quaternion = new Quaternion(); - function Matrix3() { + function Vector3( x, y, z ) { + if ( x === void 0 ) x = 0; + if ( y === void 0 ) y = 0; + if ( z === void 0 ) z = 0; - this.elements = [ - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 + this.x = x; + this.y = y; + this.z = z; - ]; + } - if ( arguments.length > 0 ) { + Object.assign( Vector3.prototype, { - console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' ); + isVector3: true, - } + set: function ( x, y, z ) { - } + if ( z === undefined ) { z = this.z; } // sprite.scale.set(x,y) - Object.assign( Matrix3.prototype, { + this.x = x; + this.y = y; + this.z = z; - isMatrix3: true, + return this; - set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { + }, - var te = this.elements; + setScalar: function ( scalar ) { - 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; + this.x = scalar; + this.y = scalar; + this.z = scalar; return this; }, - identity: function () { - - this.set( - - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 + setX: function ( x ) { - ); + this.x = x; return this; }, - clone: function () { + setY: function ( y ) { - return new this.constructor().fromArray( this.elements ); + this.y = y; - }, + return this; - copy: function ( m ) { + }, - var te = this.elements; - var me = m.elements; + setZ: function ( z ) { - 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 ]; + this.z = z; return this; }, - setFromMatrix4: function ( m ) { - - var me = m.elements; + setComponent: function ( index, value ) { - this.set( + switch ( index ) { - me[ 0 ], me[ 4 ], me[ 8 ], - me[ 1 ], me[ 5 ], me[ 9 ], - me[ 2 ], me[ 6 ], me[ 10 ] + 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; }, - applyToBufferAttribute: function () { - - var v1 = new Vector3(); - - return function applyToBufferAttribute( attribute ) { + getComponent: function ( index ) { - for ( var i = 0, l = attribute.count; i < l; i ++ ) { + switch ( index ) { - v1.x = attribute.getX( i ); - v1.y = attribute.getY( i ); - v1.z = attribute.getZ( i ); + 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 ); - v1.applyMatrix3( this ); + } - attribute.setXYZ( i, v1.x, v1.y, v1.z ); + }, - } + clone: function () { - return attribute; + return new this.constructor( this.x, this.y, this.z ); - }; + }, - }(), + copy: function ( v ) { - multiply: function ( m ) { + this.x = v.x; + this.y = v.y; + this.z = v.z; - return this.multiplyMatrices( this, m ); + return this; }, - premultiply: function ( m ) { - - return this.multiplyMatrices( m, this ); + add: function ( v, w ) { - }, + if ( w !== undefined ) { - multiplyMatrices: function ( a, b ) { + console.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); + return this.addVectors( v, w ); - var ae = a.elements; - var be = b.elements; - var te = this.elements; + } - var a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; - var a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; - var a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; + this.x += v.x; + this.y += v.y; + this.z += v.z; - var b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; - var b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; - var b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; + return this; - 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; + addScalar: function ( s ) { - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; - te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; - te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; + this.x += s; + this.y += s; + this.z += s; return this; }, - multiplyScalar: function ( s ) { - - var te = this.elements; + addVectors: function ( a, b ) { - 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; + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; return this; }, - determinant: function () { - - var te = this.elements; + addScaledVector: function ( v, s ) { - var a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], - d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], - g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; - return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; + return this; }, - getInverse: function ( matrix, throwOnDegenerate ) { + sub: function ( v, w ) { - if ( matrix && matrix.isMatrix4 ) { + if ( w !== undefined ) { - console.error( "THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument." ); + console.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); + return this.subVectors( v, w ); } - var me = matrix.elements, - te = this.elements, - - n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], - n12 = me[ 3 ], n22 = me[ 4 ], n32 = me[ 5 ], - n13 = me[ 6 ], n23 = me[ 7 ], n33 = me[ 8 ], + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; - t11 = n33 * n22 - n32 * n23, - t12 = n32 * n13 - n33 * n12, - t13 = n23 * n12 - n22 * n13, + return this; - det = n11 * t11 + n21 * t12 + n31 * t13; + }, - if ( det === 0 ) { + subScalar: function ( s ) { - var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0"; + this.x -= s; + this.y -= s; + this.z -= s; - if ( throwOnDegenerate === true ) { + return this; - throw new Error( msg ); + }, - } else { + subVectors: function ( a, b ) { - console.warn( msg ); + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; - } + return this; - return this.identity(); + }, - } + multiply: function ( v, w ) { - var detInv = 1 / det; + if ( w !== undefined ) { - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; - te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; + console.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); + return this.multiplyVectors( v, w ); - 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; + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; return this; }, - transpose: function () { - - var tmp, m = this.elements; + multiplyScalar: function ( scalar ) { - 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; + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; return this; }, - getNormalMatrix: function ( matrix4 ) { + multiplyVectors: function ( a, b ) { - return this.setFromMatrix4( matrix4 ).getInverse( this ).transpose(); + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; + + return this; }, - transposeIntoArray: function ( r ) { + applyEuler: function ( euler ) { - var m = this.elements; + if ( ! ( euler && euler.isEuler ) ) { - 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 ]; + console.error( 'THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.' ); - return this; + } - }, + return this.applyQuaternion( _quaternion.setFromEuler( euler ) ); - setUvTransform: function ( tx, ty, sx, sy, rotation, cx, cy ) { + }, - var c = Math.cos( rotation ); - var s = Math.sin( rotation ); + applyAxisAngle: function ( axis, angle ) { - 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.applyQuaternion( _quaternion.setFromAxisAngle( axis, angle ) ); }, - scale: function ( sx, sy ) { + applyMatrix3: function ( m ) { - var te = this.elements; + var x = this.x, y = this.y, z = this.z; + var e = m.elements; - te[ 0 ] *= sx; te[ 3 ] *= sx; te[ 6 ] *= sx; - te[ 1 ] *= sy; te[ 4 ] *= sy; te[ 7 ] *= sy; + 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; }, - rotate: function ( theta ) { + applyNormalMatrix: function ( m ) { - var c = Math.cos( theta ); - var s = Math.sin( theta ); + return this.applyMatrix3( m ).normalize(); - var te = this.elements; + }, - var a11 = te[ 0 ], a12 = te[ 3 ], a13 = te[ 6 ]; - var a21 = te[ 1 ], a22 = te[ 4 ], a23 = te[ 7 ]; + applyMatrix4: function ( m ) { - te[ 0 ] = c * a11 + s * a21; - te[ 3 ] = c * a12 + s * a22; - te[ 6 ] = c * a13 + s * a23; + var x = this.x, y = this.y, z = this.z; + var e = m.elements; - te[ 1 ] = - s * a11 + c * a21; - te[ 4 ] = - s * a12 + c * a22; - te[ 7 ] = - s * a13 + c * a23; + var 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; }, - translate: function ( tx, ty ) { - - var te = this.elements; + applyQuaternion: function ( q ) { - 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 ]; + var x = this.x, y = this.y, z = this.z; + var qx = q.x, qy = q.y, qz = q.z, qw = q.w; - return this; + // calculate quat * vector - }, + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = - qx * x - qy * y - qz * z; - equals: function ( matrix ) { + // calculate result * inverse quat - var te = this.elements; - var me = matrix.elements; + 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; - for ( var i = 0; i < 9; i ++ ) { + return this; - if ( te[ i ] !== me[ i ] ) return false; + }, - } + project: function ( camera ) { - return true; + return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); }, - fromArray: function ( array, offset ) { + unproject: function ( camera ) { - if ( offset === undefined ) offset = 0; + return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); - for ( var i = 0; i < 9; i ++ ) { + }, - this.elements[ i ] = array[ i + offset ]; + transformDirection: function ( m ) { - } + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction - return this; + var x = this.x, y = this.y, z = this.z; + var e = m.elements; + + this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; + this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; + this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; + + return this.normalize(); }, - toArray: function ( array, offset ) { + divide: function ( v ) { - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; - var te = this.elements; + return this; - 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 ]; + divideScalar: function ( scalar ) { - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; - array[ offset + 8 ] = te[ 8 ]; + return this.multiplyScalar( 1 / scalar ); - return array; + }, - } + min: function ( 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 ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - */ + return this; - var ImageUtils = { + }, - getDataURL: function ( image ) { + max: function ( v ) { - var canvas; + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); - if ( typeof HTMLCanvasElement == 'undefined' ) { + return this; - return image.src; + }, - } else if ( image instanceof HTMLCanvasElement ) { + clamp: function ( min, max ) { - canvas = image; + // assumes min < max, componentwise - } else { + 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 ) ); - canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.width = image.width; - canvas.height = image.height; + return this; - var context = canvas.getContext( '2d' ); + }, - if ( image instanceof ImageData ) { + clampScalar: function ( minVal, maxVal ) { - context.putImageData( image, 0, 0 ); + 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 ) ); - } else { + return this; - context.drawImage( image, 0, 0, image.width, image.height ); + }, - } + clampLength: function ( min, max ) { - } + var length = this.length(); - if ( canvas.width > 2048 || canvas.height > 2048 ) { + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - return canvas.toDataURL( 'image/jpeg', 0.6 ); + }, - } else { + floor: function () { - return canvas.toDataURL( 'image/png' ); + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); - } + return this; - } + }, - }; + ceil: function () { - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - */ + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); - var textureId = 0; + return this; - function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { + }, - Object.defineProperty( this, 'id', { value: textureId ++ } ); + round: function () { - this.uuid = _Math.generateUUID(); + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); - this.name = ''; + return this; - this.image = image !== undefined ? image : Texture.DEFAULT_IMAGE; - this.mipmaps = []; + }, - this.mapping = mapping !== undefined ? mapping : Texture.DEFAULT_MAPPING; + roundToZero: function () { - this.wrapS = wrapS !== undefined ? wrapS : ClampToEdgeWrapping; - this.wrapT = wrapT !== undefined ? wrapT : ClampToEdgeWrapping; + 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.magFilter = magFilter !== undefined ? magFilter : LinearFilter; - this.minFilter = minFilter !== undefined ? minFilter : LinearMipMapLinearFilter; + return this; - this.anisotropy = anisotropy !== undefined ? anisotropy : 1; + }, - this.format = format !== undefined ? format : RGBAFormat; - this.type = type !== undefined ? type : UnsignedByteType; + negate: function () { - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - this.center = new Vector2( 0, 0 ); - this.rotation = 0; + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; - this.matrixAutoUpdate = true; - this.matrix = new Matrix3(); + return this; - 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 !== undefined ? encoding : LinearEncoding; + dot: function ( v ) { - this.version = 0; - this.onUpdate = null; + return this.x * v.x + this.y * v.y + this.z * v.z; - } + }, - Texture.DEFAULT_IMAGE = undefined; - Texture.DEFAULT_MAPPING = UVMapping; + // TODO lengthSquared? - Texture.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + lengthSq: function () { - constructor: Texture, + return this.x * this.x + this.y * this.y + this.z * this.z; - isTexture: true, + }, - updateMatrix: function () { + length: function () { - this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); }, - clone: function () { + manhattanLength: function () { - return new this.constructor().copy( this ); + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); }, - copy: function ( source ) { + normalize: function () { - this.name = source.name; + return this.divideScalar( this.length() || 1 ); - this.image = source.image; - this.mipmaps = source.mipmaps.slice( 0 ); + }, - this.mapping = source.mapping; + setLength: function ( length ) { - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; + return this.normalize().multiplyScalar( length ); - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; + }, - this.anisotropy = source.anisotropy; + lerp: function ( v, alpha ) { - this.format = source.format; - this.type = source.type; + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - this.center.copy( source.center ); - this.rotation = source.rotation; + return this; - 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; + lerpVectors: function ( 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; }, - toJSON: function ( meta ) { - - var isRootObject = ( meta === undefined || typeof meta === 'string' ); + cross: function ( v, w ) { - if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { + if ( w !== undefined ) { - return meta.textures[ this.uuid ]; + console.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); + return this.crossVectors( v, w ); } - var output = { - - metadata: { - version: 4.5, - type: 'Texture', - generator: 'Texture.toJSON' - }, + return this.crossVectors( this, v ); - uuid: this.uuid, - name: this.name, + }, - mapping: this.mapping, + crossVectors: function ( a, b ) { - repeat: [ this.repeat.x, this.repeat.y ], - offset: [ this.offset.x, this.offset.y ], - center: [ this.center.x, this.center.y ], - rotation: this.rotation, + var ax = a.x, ay = a.y, az = a.z; + var bx = b.x, by = b.y, bz = b.z; - wrap: [ this.wrapS, this.wrapT ], + this.x = ay * bz - az * by; + this.y = az * bx - ax * bz; + this.z = ax * by - ay * bx; - format: this.format, - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, + return this; - flipY: this.flipY + }, - }; + projectOnVector: function ( v ) { - if ( this.image !== undefined ) { + var denominator = v.lengthSq(); - // TODO: Move to THREE.Image + if ( denominator === 0 ) { return this.set( 0, 0, 0 ); } - var image = this.image; + var scalar = v.dot( this ) / denominator; - if ( image.uuid === undefined ) { + return this.copy( v ).multiplyScalar( scalar ); - image.uuid = _Math.generateUUID(); // UGH + }, - } + projectOnPlane: function ( planeNormal ) { - if ( ! isRootObject && meta.images[ image.uuid ] === undefined ) { + _vector.copy( this ).projectOnVector( planeNormal ); - var url; + return this.sub( _vector ); - if ( Array.isArray( image ) ) { + }, - // process array of images e.g. CubeTexture + reflect: function ( normal ) { - url = []; + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length - for ( var i = 0, l = image.length; i < l; i ++ ) { + return this.sub( _vector.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - url.push( ImageUtils.getDataURL( image[ i ] ) ); + }, - } + angleTo: function ( v ) { - } else { + var denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - // process single image + if ( denominator === 0 ) { return Math.PI / 2; } - url = ImageUtils.getDataURL( image ); + var theta = this.dot( v ) / denominator; - } + // clamp, to handle numerical problems - meta.images[ image.uuid ] = { - uuid: image.uuid, - url: url - }; + return Math.acos( MathUtils.clamp( theta, - 1, 1 ) ); - } + }, - output.image = image.uuid; + distanceTo: function ( v ) { - } + return Math.sqrt( this.distanceToSquared( v ) ); - if ( ! isRootObject ) { + }, - meta.textures[ this.uuid ] = output; + distanceToSquared: function ( v ) { - } + var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - return output; + return dx * dx + dy * dy + dz * dz; }, - dispose: function () { + manhattanDistanceTo: function ( v ) { - this.dispatchEvent( { type: 'dispose' } ); + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); }, - transformUv: function ( uv ) { - - if ( this.mapping !== UVMapping ) return uv; + setFromSpherical: function ( s ) { - uv.applyMatrix3( this.matrix ); + return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); - if ( uv.x < 0 || uv.x > 1 ) { + }, - switch ( this.wrapS ) { + setFromSphericalCoords: function ( radius, phi, theta ) { - case RepeatWrapping: + var sinPhiRadius = Math.sin( phi ) * radius; - uv.x = uv.x - Math.floor( uv.x ); - break; + this.x = sinPhiRadius * Math.sin( theta ); + this.y = Math.cos( phi ) * radius; + this.z = sinPhiRadius * Math.cos( theta ); - case ClampToEdgeWrapping: + return this; - uv.x = uv.x < 0 ? 0 : 1; - break; + }, - case MirroredRepeatWrapping: + setFromCylindrical: function ( c ) { - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { + return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); - uv.x = Math.ceil( uv.x ) - uv.x; + }, - } else { + setFromCylindricalCoords: function ( radius, theta, y ) { - uv.x = uv.x - Math.floor( uv.x ); + this.x = radius * Math.sin( theta ); + this.y = y; + this.z = radius * Math.cos( theta ); - } - break; + return this; - } + }, - } + setFromMatrixPosition: function ( m ) { - if ( uv.y < 0 || uv.y > 1 ) { + var e = m.elements; - switch ( this.wrapT ) { + this.x = e[ 12 ]; + this.y = e[ 13 ]; + this.z = e[ 14 ]; - case RepeatWrapping: + return this; - uv.y = uv.y - Math.floor( uv.y ); - break; + }, - case ClampToEdgeWrapping: + setFromMatrixScale: function ( m ) { - uv.y = uv.y < 0 ? 0 : 1; - break; + var sx = this.setFromMatrixColumn( m, 0 ).length(); + var sy = this.setFromMatrixColumn( m, 1 ).length(); + var sz = this.setFromMatrixColumn( m, 2 ).length(); - case MirroredRepeatWrapping: + this.x = sx; + this.y = sy; + this.z = sz; - if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { + return this; - uv.y = Math.ceil( uv.y ) - uv.y; + }, - } else { + setFromMatrixColumn: function ( m, index ) { - uv.y = uv.y - Math.floor( uv.y ); + return this.fromArray( m.elements, index * 4 ); - } - break; + }, - } + setFromMatrix3Column: function ( m, index ) { - } + return this.fromArray( m.elements, index * 3 ); - if ( this.flipY ) { + }, - uv.y = 1 - uv.y; + equals: function ( v ) { - } + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - return uv; + }, - } + fromArray: function ( array, offset ) { - } ); + if ( offset === undefined ) { offset = 0; } - Object.defineProperty( Texture.prototype, "needsUpdate", { + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; - set: function ( value ) { + return this; - if ( value === true ) this.version ++; + }, - } + toArray: function ( array, offset ) { - } ); + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } - /** - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author philogb / http://blog.thejit.org/ - * @author mikael emtinger / http://gomo.se/ - * @author egraether / http://egraether.com/ - * @author WestLangley / http://github.com/WestLangley - */ + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; - function Vector4( x, y, z, w ) { + return array; - this.x = x || 0; - this.y = y || 0; - this.z = z || 0; - this.w = ( w !== undefined ) ? w : 1; + }, - } + fromBufferAttribute: function ( attribute, index, offset ) { - Object.assign( Vector4.prototype, { + if ( offset !== undefined ) { - isVector4: true, + console.warn( 'THREE.Vector3: offset has been removed from .fromBufferAttribute().' ); - set: function ( x, y, z, w ) { + } - this.x = x; - this.y = y; - this.z = z; - this.w = w; + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); return this; }, - setScalar: function ( scalar ) { + random: function () { - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); return this; - }, + } - setX: function ( x ) { + } ); - this.x = x; + var _v1 = new Vector3(); + var _m1 = new Matrix4(); + var _zero = new Vector3( 0, 0, 0 ); + var _one = new Vector3( 1, 1, 1 ); + var _x = new Vector3(); + var _y = new Vector3(); + var _z = new Vector3(); - return this; + function Matrix4() { - }, + this.elements = [ - setY: function ( y ) { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - this.y = y; + ]; - return this; + if ( arguments.length > 0 ) { - }, + console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' ); - setZ: function ( z ) { + } - this.z = z; + } - return this; + Object.assign( Matrix4.prototype, { - }, + isMatrix4: true, - setW: function ( w ) { + set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - this.w = w; + var te = this.elements; + + te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; + te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; + te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; + te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; return this; }, - setComponent: function ( index, value ) { + identity: function () { - switch ( index ) { + this.set( - 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 ); + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - } + ); return this; }, - getComponent: function ( index ) { - - switch ( index ) { - - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); - - } - - }, - clone: function () { - return new this.constructor( this.x, this.y, this.z, this.w ); + return new Matrix4().fromArray( this.elements ); }, - copy: function ( v ) { + copy: function ( m ) { - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; + var te = this.elements; + var 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; }, - add: function ( 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 ); + copyPosition: function ( m ) { - } + var te = this.elements, me = m.elements; - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; return this; }, - addScalar: function ( s ) { + extractBasis: function ( xAxis, yAxis, zAxis ) { - this.x += s; - this.y += s; - this.z += s; - this.w += s; + xAxis.setFromMatrixColumn( this, 0 ); + yAxis.setFromMatrixColumn( this, 1 ); + zAxis.setFromMatrixColumn( this, 2 ); return this; }, - addVectors: function ( a, b ) { + makeBasis: function ( xAxis, yAxis, zAxis ) { - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; + this.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; }, - addScaledVector: function ( v, s ) { + extractRotation: function ( m ) { - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; - this.w += v.w * s; + // this method does not support reflection matrices + + var te = this.elements; + var me = m.elements; + + var scaleX = 1 / _v1.setFromMatrixColumn( m, 0 ).length(); + var scaleY = 1 / _v1.setFromMatrixColumn( m, 1 ).length(); + var scaleZ = 1 / _v1.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; }, - sub: function ( v, w ) { + makeRotationFromEuler: function ( euler ) { - if ( w !== undefined ) { + if ( ! ( euler && euler.isEuler ) ) { - console.warn( 'THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); - return this.subVectors( v, w ); + console.error( 'THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.' ); } - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; + var te = this.elements; - return this; + var x = euler.x, y = euler.y, z = euler.z; + var a = Math.cos( x ), b = Math.sin( x ); + var c = Math.cos( y ), d = Math.sin( y ); + var e = Math.cos( z ), f = Math.sin( z ); - }, + if ( euler.order === 'XYZ' ) { - subScalar: function ( s ) { + var ae = a * e, af = a * f, be = b * e, bf = b * f; - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; - return this; + 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; - subVectors: function ( a, b ) { + } else if ( euler.order === 'YXZ' ) { - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; + var ce = c * e, cf = c * f, de = d * e, df = d * f; - return this; + 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; - multiplyScalar: function ( scalar ) { + te[ 2 ] = cf * b - de; + te[ 6 ] = df + ce * b; + te[ 10 ] = a * c; - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; + } else if ( euler.order === 'ZXY' ) { - return this; + var ce$1 = c * e, cf$1 = c * f, de$1 = d * e, df$1 = d * f; - }, + te[ 0 ] = ce$1 - df$1 * b; + te[ 4 ] = - a * f; + te[ 8 ] = de$1 + cf$1 * b; - applyMatrix4: function ( m ) { + te[ 1 ] = cf$1 + de$1 * b; + te[ 5 ] = a * e; + te[ 9 ] = df$1 - ce$1 * b; - var x = this.x, y = this.y, z = this.z, w = this.w; - var e = m.elements; + te[ 2 ] = - a * d; + te[ 6 ] = b; + te[ 10 ] = a * c; - 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; + } else if ( euler.order === 'ZYX' ) { - return this; + var ae$1 = a * e, af$1 = a * f, be$1 = b * e, bf$1 = b * f; - }, + te[ 0 ] = c * e; + te[ 4 ] = be$1 * d - af$1; + te[ 8 ] = ae$1 * d + bf$1; - divideScalar: function ( scalar ) { + te[ 1 ] = c * f; + te[ 5 ] = bf$1 * d + ae$1; + te[ 9 ] = af$1 * d - be$1; - return this.multiplyScalar( 1 / scalar ); + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; - }, + } else if ( euler.order === 'YZX' ) { - setAxisAngleFromQuaternion: function ( q ) { + var ac = a * c, ad = a * d, bc = b * c, bd = b * d; - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + te[ 0 ] = c * e; + te[ 4 ] = bd - ac * f; + te[ 8 ] = bc * f + ad; - // q is assumed to be normalized + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; - this.w = 2 * Math.acos( q.w ); + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; - var s = Math.sqrt( 1 - q.w * q.w ); + } else if ( euler.order === 'XZY' ) { - if ( s < 0.0001 ) { + var ac$1 = a * c, ad$1 = a * d, bc$1 = b * c, bd$1 = b * d; - this.x = 1; - this.y = 0; - this.z = 0; + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; - } else { + te[ 1 ] = ac$1 * f + bd$1; + te[ 5 ] = a * e; + te[ 9 ] = ad$1 * f - bc$1; - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; + te[ 2 ] = bc$1 * f - ad$1; + te[ 6 ] = b * e; + te[ 10 ] = bd$1 * f + ac$1; } + // 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; }, - setAxisAngleFromRotationMatrix: function ( m ) { + makeRotationFromQuaternion: function ( q ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + return this.compose( _zero, q, _one ); - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + }, - var angle, x, y, z, // variables for result - epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + lookAt: function ( eye, target, up ) { - te = m.elements, + var te = this.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 ]; + _z.subVectors( eye, target ); - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { + if ( _z.lengthSq() === 0 ) { - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms + // eye and target are in the same position - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + _z.z = 1; - // this singularity is identity matrix so angle = 0 + } - this.set( 1, 0, 0, 0 ); + _z.normalize(); + _x.crossVectors( up, _z ); - return this; // zero angle, arbitrary axis + if ( _x.lengthSq() === 0 ) { - } + // up and z are parallel - // otherwise this singularity is angle = 180 + if ( Math.abs( up.z ) === 1 ) { - angle = Math.PI; + _z.x += 0.0001; - var xx = ( m11 + 1 ) / 2; - var yy = ( m22 + 1 ) / 2; - var zz = ( m33 + 1 ) / 2; - var xy = ( m12 + m21 ) / 4; - var xz = ( m13 + m31 ) / 4; - var yz = ( m23 + m32 ) / 4; + } else { - if ( ( xx > yy ) && ( xx > zz ) ) { + _z.z += 0.0001; - // m11 is the largest diagonal term + } - if ( xx < epsilon ) { + _z.normalize(); + _x.crossVectors( up, _z ); - x = 0; - y = 0.707106781; - z = 0.707106781; + } - } else { + _x.normalize(); + _y.crossVectors( _z, _x ); - x = Math.sqrt( xx ); - y = xy / x; - z = xz / 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; - } else if ( yy > zz ) { + }, - // m22 is the largest diagonal term + multiply: function ( m, n ) { - if ( yy < epsilon ) { + if ( n !== undefined ) { - x = 0.707106781; - y = 0; - z = 0.707106781; + console.warn( 'THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); + return this.multiplyMatrices( m, n ); - } else { + } - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; + return this.multiplyMatrices( this, m ); - } + }, - } else { + premultiply: function ( m ) { - // m33 is the largest diagonal term so base result on this + return this.multiplyMatrices( m, this ); - if ( zz < epsilon ) { + }, - x = 0.707106781; - y = 0.707106781; - z = 0; + multiplyMatrices: function ( a, b ) { - } else { + var ae = a.elements; + var be = b.elements; + var te = this.elements; - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; + var a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; + var a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; + var a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; + var a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - } + var b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; + var b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; + var b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; + var b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - } + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - this.set( x, y, z, angle ); + 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; - return this; // return 180 deg rotation + 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; - // as we have reached here there are no singularities so we can handle normally + return this; - var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + }, - if ( Math.abs( s ) < 0.001 ) s = 1; + multiplyScalar: function ( s ) { - // 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 + var te = this.elements; - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + 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; }, - min: function ( 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 ); + determinant: function () { - return this; + var te = this.elements; - }, + var n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; + var n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; + var n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; + var n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - max: function ( v ) { + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - 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 ( + 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 + ) - return this; + ); }, - clamp: function ( min, max ) { + transpose: function () { - // assumes min < max, componentwise + var te = this.elements; + var tmp; - 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 ) ); + 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; }, - clampScalar: function () { - - var min, max; + setPosition: function ( x, y, z ) { - return function clampScalar( minVal, maxVal ) { + var te = this.elements; - if ( min === undefined ) { + if ( x.isVector3 ) { - min = new Vector4(); - max = new Vector4(); + te[ 12 ] = x.x; + te[ 13 ] = x.y; + te[ 14 ] = x.z; - } + } else { - min.set( minVal, minVal, minVal, minVal ); - max.set( maxVal, maxVal, maxVal, maxVal ); + te[ 12 ] = x; + te[ 13 ] = y; + te[ 14 ] = z; - return this.clamp( min, max ); + } - }; + return this; - }(), + }, - clampLength: function ( min, max ) { + getInverse: function ( m, throwOnDegenerate ) { - var length = this.length(); + if ( throwOnDegenerate !== undefined ) { - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + console.warn( "THREE.Matrix4: .getInverse() can no longer be configured to throw on degenerate." ); - }, + } - floor: function () { + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + var te = this.elements, + me = m.elements, - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - this.w = Math.floor( this.w ); + n11 = me[ 0 ], n21 = me[ 1 ], n31 = me[ 2 ], n41 = me[ 3 ], + n12 = me[ 4 ], n22 = me[ 5 ], n32 = me[ 6 ], n42 = me[ 7 ], + n13 = me[ 8 ], n23 = me[ 9 ], n33 = me[ 10 ], n43 = me[ 11 ], + n14 = me[ 12 ], n24 = me[ 13 ], n34 = me[ 14 ], n44 = me[ 15 ], - return this; + 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; - }, + var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - ceil: function () { + if ( det === 0 ) { return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); } - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - this.w = Math.ceil( this.w ); + var detInv = 1 / det; - return this; + 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; - round: function () { + 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; - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - this.w = Math.round( this.w ); + 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; }, - roundToZero: function () { + scale: function ( v ) { - 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 ); + var te = this.elements; + var x = v.x, y = v.y, z = v.z; + + te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; + te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; + te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; + te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; return this; }, - negate: function () { + getMaxScaleOnAxis: function () { - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - this.w = - this.w; + var te = this.elements; - return this; + var scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; + var scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; + var scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + + return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); }, - dot: function ( v ) { + makeTranslation: function ( x, y, z ) { - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + this.set( - }, + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 - lengthSq: function () { + ); - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + return this; }, - length: function () { + makeRotationX: function ( theta ) { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + var c = Math.cos( theta ), s = Math.sin( theta ); - }, + this.set( - manhattanLength: function () { + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, + 0, 0, 0, 1 - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + ); + + return this; }, - normalize: function () { + makeRotationY: function ( theta ) { - return this.divideScalar( this.length() || 1 ); + var c = Math.cos( theta ), s = Math.sin( theta ); - }, + this.set( - setLength: function ( length ) { + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 - return this.normalize().multiplyScalar( length ); + ); + + return this; }, - lerp: function ( v, alpha ) { + makeRotationZ: function ( theta ) { - 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; + var c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + + ); return this; }, - lerpVectors: function ( v1, v2, alpha ) { + makeRotationAxis: function ( axis, angle ) { + + // Based on http://www.gamedev.net/reference/articles/article1199.asp - return this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 ); + var c = Math.cos( angle ); + var s = Math.sin( angle ); + var t = 1 - c; + var x = axis.x, y = axis.y, z = axis.z; + var tx = t * x, ty = t * y; - }, + this.set( - equals: function ( v ) { + 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 ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + ); + + return this; }, - fromArray: function ( array, offset ) { + makeScale: function ( x, y, z ) { - if ( offset === undefined ) offset = 0; + this.set( - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 + + ); return this; }, - toArray: function ( array, offset ) { + makeShear: function ( x, y, z ) { - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; + this.set( - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; + 1, y, z, 0, + x, 1, z, 0, + x, y, 1, 0, + 0, 0, 0, 1 - return array; + ); + + return this; }, - fromBufferAttribute: function ( attribute, index, offset ) { + compose: function ( position, quaternion, scale ) { - if ( offset !== undefined ) { + var te = this.elements; - console.warn( 'THREE.Vector4: offset has been removed from .fromBufferAttribute().' ); + var x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; + var x2 = x + x, y2 = y + y, z2 = z + z; + var xx = x * x2, xy = x * y2, xz = x * z2; + var yy = y * y2, yz = y * z2, zz = z * z2; + var wx = w * x2, wy = w * y2, wz = w * z2; - } + var sx = scale.x, sy = scale.y, sz = scale.z; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); + te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; + te[ 1 ] = ( xy + wz ) * sx; + te[ 2 ] = ( xz - wy ) * sx; + te[ 3 ] = 0; - return this; + 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; - /** - * @author szimek / https://github.com/szimek/ - * @author alteredq / http://alteredqualia.com/ - * @author Marius Kintel / https://github.com/kintel - */ + return this; - /* - In options, we can specify: - * Texture parameters for an auto-generated target texture - * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers - */ - function WebGLRenderTarget( width, height, options ) { + }, - this.width = width; - this.height = height; + decompose: function ( position, quaternion, scale ) { - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; + var te = this.elements; - this.viewport = new Vector4( 0, 0, width, height ); + var sx = _v1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + var sy = _v1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + var sz = _v1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); - options = options || {}; + // if determine is negative, we need to invert one scale + var det = this.determinant(); + if ( det < 0 ) { sx = - sx; } - if ( options.minFilter === undefined ) options.minFilter = LinearFilter; + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; - this.texture = new Texture( undefined, undefined, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); + // scale the rotation part + _m1.copy( this ); - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : true; + var invSX = 1 / sx; + var invSY = 1 / sy; + var invSZ = 1 / sz; - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; - this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; + _m1.elements[ 0 ] *= invSX; + _m1.elements[ 1 ] *= invSX; + _m1.elements[ 2 ] *= invSX; - } + _m1.elements[ 4 ] *= invSY; + _m1.elements[ 5 ] *= invSY; + _m1.elements[ 6 ] *= invSY; - WebGLRenderTarget.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + _m1.elements[ 8 ] *= invSZ; + _m1.elements[ 9 ] *= invSZ; + _m1.elements[ 10 ] *= invSZ; - constructor: WebGLRenderTarget, + quaternion.setFromRotationMatrix( _m1 ); - isWebGLRenderTarget: true, + scale.x = sx; + scale.y = sy; + scale.z = sz; - setSize: function ( width, height ) { + return this; - if ( this.width !== width || this.height !== height ) { + }, - this.width = width; - this.height = height; + makePerspective: function ( left, right, top, bottom, near, far ) { - this.dispose(); + if ( far === undefined ) { + + console.warn( 'THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.' ); } - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); + var te = this.elements; + var x = 2 * near / ( right - left ); + var y = 2 * near / ( top - bottom ); - }, + var a = ( right + left ) / ( right - left ); + var b = ( top + bottom ) / ( top - bottom ); + var c = - ( far + near ) / ( far - near ); + var d = - 2 * far * near / ( far - near ); - clone: function () { + 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 new this.constructor().copy( this ); + return this; }, - copy: function ( source ) { - - this.width = source.width; - this.height = source.height; + makeOrthographic: function ( left, right, top, bottom, near, far ) { - this.viewport.copy( source.viewport ); + var te = this.elements; + var w = 1.0 / ( right - left ); + var h = 1.0 / ( top - bottom ); + var p = 1.0 / ( far - near ); - this.texture = source.texture.clone(); + var x = ( right + left ) * w; + var y = ( top + bottom ) * h; + var z = ( far + near ) * p; - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; - this.depthTexture = source.depthTexture; + 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; }, - dispose: function () { - - this.dispatchEvent( { type: 'dispose' } ); + equals: function ( matrix ) { - } + var te = this.elements; + var me = matrix.elements; - } ); + for ( var i = 0; i < 16; i ++ ) { - /** - * @author alteredq / http://alteredqualia.com - */ + if ( te[ i ] !== me[ i ] ) { return false; } - function WebGLRenderTargetCube( width, height, options ) { + } - WebGLRenderTarget.call( this, width, height, options ); + return true; - this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 - this.activeMipMapLevel = 0; + }, - } + fromArray: function ( array, offset ) { - WebGLRenderTargetCube.prototype = Object.create( WebGLRenderTarget.prototype ); - WebGLRenderTargetCube.prototype.constructor = WebGLRenderTargetCube; + if ( offset === undefined ) { offset = 0; } - WebGLRenderTargetCube.prototype.isWebGLRenderTargetCube = true; + for ( var i = 0; i < 16; i ++ ) { - /** - * @author alteredq / http://alteredqualia.com/ - */ + this.elements[ i ] = array[ i + offset ]; - function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { + } - Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + return this; - this.image = { data: data, width: width, height: height }; + }, - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + toArray: function ( array, offset ) { - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } - } + var te = this.elements; - DataTexture.prototype = Object.create( Texture.prototype ); - DataTexture.prototype.constructor = DataTexture; + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; - DataTexture.prototype.isDataTexture = true; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; - /** - * @author bhouston / http://clara.io - * @author WestLangley / http://github.com/WestLangley - */ + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; - function Box3( min, max ) { + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; - this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity ); - this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity ); + return array; - } + } - Object.assign( Box3.prototype, { + } ); - isBox3: true, + var _matrix = new Matrix4(); + var _quaternion$1 = new Quaternion(); - set: function ( min, max ) { + function Euler( x, y, z, order ) { + if ( x === void 0 ) x = 0; + if ( y === void 0 ) y = 0; + if ( z === void 0 ) z = 0; + if ( order === void 0 ) order = Euler.DefaultOrder; - this.min.copy( min ); - this.max.copy( max ); - return this; + this._x = x; + this._y = y; + this._z = z; + this._order = order; - }, + } - setFromArray: function ( array ) { + Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; - var minX = + Infinity; - var minY = + Infinity; - var minZ = + Infinity; + Euler.DefaultOrder = 'XYZ'; - var maxX = - Infinity; - var maxY = - Infinity; - var maxZ = - Infinity; + Object.defineProperties( Euler.prototype, { - for ( var i = 0, l = array.length; i < l; i += 3 ) { + x: { - var x = array[ i ]; - var y = array[ i + 1 ]; - var z = array[ i + 2 ]; + get: function () { - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + return this._x; - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + }, - } + set: function ( value ) { - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + this._x = value; + this._onChangeCallback(); - return this; + } }, - setFromBufferAttribute: function ( attribute ) { - - var minX = + Infinity; - var minY = + Infinity; - var minZ = + Infinity; + y: { - var maxX = - Infinity; - var maxY = - Infinity; - var maxZ = - Infinity; + get: function () { - for ( var i = 0, l = attribute.count; i < l; i ++ ) { + return this._y; - var x = attribute.getX( i ); - var y = attribute.getY( i ); - var z = attribute.getZ( i ); + }, - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + set: function ( value ) { - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + this._y = value; + this._onChangeCallback(); } - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + }, - return this; + z: { - }, + get: function () { - setFromPoints: function ( points ) { + return this._z; - this.makeEmpty(); + }, - for ( var i = 0, il = points.length; i < il; i ++ ) { + set: function ( value ) { - this.expandByPoint( points[ i ] ); + this._z = value; + this._onChangeCallback(); } - return this; - }, - setFromCenterAndSize: function () { + order: { - var v1 = new Vector3(); + get: function () { - return function setFromCenterAndSize( center, size ) { + return this._order; - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); + }, - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + set: function ( value ) { - return this; + this._order = value; + this._onChangeCallback(); - }; + } - }(), + } - setFromObject: function ( object ) { + } ); - this.makeEmpty(); + Object.assign( Euler.prototype, { - return this.expandByObject( object ); + isEuler: true, + + set: function ( x, y, z, order ) { + + this._x = x; + this._y = y; + this._z = z; + this._order = order || this._order; + + this._onChangeCallback(); + + return this; }, clone: function () { - return new this.constructor().copy( this ); + return new this.constructor( this._x, this._y, this._z, this._order ); }, - copy: function ( box ) { + copy: function ( euler ) { - this.min.copy( box.min ); - this.max.copy( box.max ); + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; + + this._onChangeCallback(); return this; }, - makeEmpty: function () { - - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; + setFromRotationMatrix: function ( m, order, update ) { - return this; + var clamp = MathUtils.clamp; - }, + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - isEmpty: function () { + var te = m.elements; + var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; + var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; + var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes + order = order || this._order; - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + switch ( order ) { - }, + case 'XYZ': - getCenter: function ( target ) { + this._y = Math.asin( clamp( m13, - 1, 1 ) ); - if ( target === undefined ) { + if ( Math.abs( m13 ) < 0.9999999 ) { - console.warn( 'THREE.Box3: .getCenter() target is now required' ); - target = new Vector3(); + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); - } + } else { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + this._x = Math.atan2( m32, m22 ); + this._z = 0; - }, + } - getSize: function ( target ) { + break; - if ( target === undefined ) { + case 'YXZ': - console.warn( 'THREE.Box3: .getSize() target is now required' ); - target = new Vector3(); + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); - } + if ( Math.abs( m23 ) < 0.9999999 ) { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); - }, + } else { - expandByPoint: function ( point ) { + this._y = Math.atan2( - m31, m11 ); + this._z = 0; - this.min.min( point ); - this.max.max( point ); + } - return this; + break; - }, + case 'ZXY': - expandByVector: function ( vector ) { + this._x = Math.asin( clamp( m32, - 1, 1 ) ); - this.min.sub( vector ); - this.max.add( vector ); + if ( Math.abs( m32 ) < 0.9999999 ) { - return this; + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); - }, + } else { - expandByScalar: function ( scalar ) { + this._y = 0; + this._z = Math.atan2( m21, m11 ); - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + } - return this; + break; - }, + case 'ZYX': - expandByObject: function () { + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms + if ( Math.abs( m31 ) < 0.9999999 ) { - var scope, i, l; + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); - var v1 = new Vector3(); + } else { - function traverse( node ) { + this._x = 0; + this._z = Math.atan2( - m12, m22 ); - var geometry = node.geometry; + } - if ( geometry !== undefined ) { + break; - if ( geometry.isGeometry ) { + case 'YZX': - var vertices = geometry.vertices; + this._z = Math.asin( clamp( m21, - 1, 1 ) ); - for ( i = 0, l = vertices.length; i < l; i ++ ) { + if ( Math.abs( m21 ) < 0.9999999 ) { - v1.copy( vertices[ i ] ); - v1.applyMatrix4( node.matrixWorld ); + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); - scope.expandByPoint( v1 ); + } else { - } + this._x = 0; + this._y = Math.atan2( m13, m33 ); - } else if ( geometry.isBufferGeometry ) { + } - var attribute = geometry.attributes.position; + break; - if ( attribute !== undefined ) { + case 'XZY': - for ( i = 0, l = attribute.count; i < l; i ++ ) { + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); - v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld ); + if ( Math.abs( m12 ) < 0.9999999 ) { - scope.expandByPoint( v1 ); + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); - } + } else { - } + this._x = Math.atan2( - m23, m33 ); + this._y = 0; } - } + break; - } + default: - return function expandByObject( object ) { + console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); - scope = this; + } - object.updateMatrixWorld( true ); + this._order = order; - object.traverse( traverse ); + if ( update !== false ) { this._onChangeCallback(); } - return this; + return this; - }; + }, - }(), + setFromQuaternion: function ( q, order, update ) { - containsPoint: function ( point ) { + _matrix.makeRotationFromQuaternion( q ); - 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; + return this.setFromRotationMatrix( _matrix, order, update ); }, - containsBox: function ( box ) { + setFromVector3: function ( v, order ) { - 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; + return this.set( v.x, v.y, v.z, order || this._order ); }, - getParameter: function ( point, target ) { - - // This can potentially have a divide by zero if the box - // has a size dimension of 0. - - if ( target === undefined ) { + reorder: function ( newOrder ) { - console.warn( 'THREE.Box3: .getParameter() target is now required' ); - target = new Vector3(); + // WARNING: this discards revolution information -bhouston - } + _quaternion$1.setFromEuler( this ); - 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 ) - ); + return this.setFromQuaternion( _quaternion$1, newOrder ); }, - intersectsBox: function ( box ) { + equals: function ( euler ) { - // 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; + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); }, - intersectsSphere: ( function () { + fromArray: function ( array ) { - var closestPoint = new Vector3(); + this._x = array[ 0 ]; + this._y = array[ 1 ]; + this._z = array[ 2 ]; + if ( array[ 3 ] !== undefined ) { this._order = array[ 3 ]; } - return function intersectsSphere( sphere ) { + this._onChangeCallback(); - // Find the point on the AABB closest to the sphere center. - this.clampPoint( sphere.center, closestPoint ); + return this; - // If that point is inside the sphere, the AABB and sphere intersect. - return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); + }, - }; + toArray: function ( array, offset ) { - } )(), + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } - intersectsPlane: function ( plane ) { + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; - // 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. + return array; - var min, max; + }, - if ( plane.normal.x > 0 ) { + toVector3: function ( optionalResult ) { - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; + if ( optionalResult ) { + + return optionalResult.set( this._x, this._y, this._z ); } else { - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; + return new Vector3( this._x, this._y, this._z ); } - if ( plane.normal.y > 0 ) { + }, - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; + _onChange: function ( callback ) { - } else { + this._onChangeCallback = callback; - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; + return this; - } + }, - if ( plane.normal.z > 0 ) { + _onChangeCallback: function () {} - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; + } ); - } else { + function Layers() { - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; + this.mask = 1 | 0; - } + } - return ( min <= - plane.constant && max >= - plane.constant ); + Object.assign( Layers.prototype, { - }, + set: function ( channel ) { - intersectsTriangle: ( function () { + this.mask = 1 << channel | 0; - // triangle centered vertices - var v0 = new Vector3(); - var v1 = new Vector3(); - var v2 = new Vector3(); + }, - // triangle edge vectors - var f0 = new Vector3(); - var f1 = new Vector3(); - var f2 = new Vector3(); + enable: function ( channel ) { - var testAxis = new Vector3(); + this.mask |= 1 << channel | 0; - var center = new Vector3(); - var extents = new Vector3(); + }, - var triangleNormal = new Vector3(); + enableAll: function () { - function satForAxes( axes ) { + this.mask = 0xffffffff | 0; - var i, j; + }, - for ( i = 0, j = axes.length - 3; i <= j; i += 3 ) { + toggle: function ( channel ) { - testAxis.fromArray( axes, i ); - // project the aabb onto the seperating axis - var 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 - var p0 = v0.dot( testAxis ); - var p1 = v1.dot( testAxis ); - var 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 ) { + this.mask ^= 1 << channel | 0; - // points of the projected triangle are outside the projected half-length of the aabb - // the axis is seperating and we can exit - return false; - - } + }, - } + disable: function ( channel ) { - return true; + this.mask &= ~ ( 1 << channel | 0 ); - } + }, - return function intersectsTriangle( triangle ) { + disableAll: function () { - if ( this.isEmpty() ) { + this.mask = 0; - return false; + }, - } + test: function ( layers ) { - // compute box center and extents - this.getCenter( center ); - extents.subVectors( this.max, center ); + return ( this.mask & layers.mask ) !== 0; - // translate triangle to aabb origin - v0.subVectors( triangle.a, center ); - v1.subVectors( triangle.b, center ); - v2.subVectors( triangle.c, center ); + } - // compute edge vectors for triangle - f0.subVectors( v1, v0 ); - f1.subVectors( v2, v1 ); - f2.subVectors( v0, v2 ); + } ); - // 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) - var 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 ) ) { + var _object3DId = 0; - return false; + var _v1$1 = new Vector3(); + var _q1 = new Quaternion(); + var _m1$1 = new Matrix4(); + var _target = new Vector3(); - } + var _position = new Vector3(); + var _scale = new Vector3(); + var _quaternion$2 = new Quaternion(); - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes ) ) { + var _xAxis = new Vector3( 1, 0, 0 ); + var _yAxis = new Vector3( 0, 1, 0 ); + var _zAxis = new Vector3( 0, 0, 1 ); - return false; + var _addedEvent = { type: 'added' }; + var _removedEvent = { type: 'removed' }; - } + function Object3D() { - // 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 ); + Object.defineProperty( this, 'id', { value: _object3DId ++ } ); - }; + this.uuid = MathUtils.generateUUID(); - } )(), + this.name = ''; + this.type = 'Object3D'; - clampPoint: function ( point, target ) { + this.parent = null; + this.children = []; - if ( target === undefined ) { + this.up = Object3D.DefaultUp.clone(); - console.warn( 'THREE.Box3: .clampPoint() target is now required' ); - target = new Vector3(); + var position = new Vector3(); + var rotation = new Euler(); + var quaternion = new Quaternion(); + var scale = new Vector3( 1, 1, 1 ); - } + function onRotationChange() { - return target.copy( point ).clamp( this.min, this.max ); + quaternion.setFromEuler( rotation, false ); - }, + } - distanceToPoint: function () { + function onQuaternionChange() { - var v1 = new Vector3(); + rotation.setFromQuaternion( quaternion, undefined, false ); - return function distanceToPoint( point ) { + } - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); + 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(); - getBoundingSphere: function () { + this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; + this.matrixWorldNeedsUpdate = false; - var v1 = new Vector3(); + this.layers = new Layers(); + this.visible = true; - return function getBoundingSphere( target ) { + this.castShadow = false; + this.receiveShadow = false; - if ( target === undefined ) { + this.frustumCulled = true; + this.renderOrder = 0; - console.warn( 'THREE.Box3: .getBoundingSphere() target is now required' ); - target = new Sphere(); + this.userData = {}; - } + } - this.getCenter( target.center ); + Object3D.DefaultUp = new Vector3( 0, 1, 0 ); + Object3D.DefaultMatrixAutoUpdate = true; - target.radius = this.getSize( v1 ).length() * 0.5; + Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - return target; + constructor: Object3D, - }; + isObject3D: true, - }(), + onBeforeRender: function () {}, + onAfterRender: function () {}, - intersect: function ( box ) { + applyMatrix4: function ( matrix ) { - this.min.max( box.min ); - this.max.min( box.max ); + if ( this.matrixAutoUpdate ) { this.updateMatrix(); } - // 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(); + this.matrix.premultiply( matrix ); - return this; + this.matrix.decompose( this.position, this.quaternion, this.scale ); }, - union: function ( box ) { + applyQuaternion: function ( q ) { - this.min.min( box.min ); - this.max.max( box.max ); + this.quaternion.premultiply( q ); return this; }, - applyMatrix4: function () { - - var points = [ - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3(), - new Vector3() - ]; - - return function applyMatrix4( matrix ) { + setRotationFromAxisAngle: function ( axis, angle ) { - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; + // assumes axis is normalized - // 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.quaternion.setFromAxisAngle( axis, angle ); - this.setFromPoints( points ); + }, - return this; + setRotationFromEuler: function ( euler ) { - }; + this.quaternion.setFromEuler( euler, true ); - }(), + }, - translate: function ( offset ) { + setRotationFromMatrix: function ( m ) { - this.min.add( offset ); - this.max.add( offset ); + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - return this; + this.quaternion.setFromRotationMatrix( m ); }, - equals: function ( box ) { - - return box.min.equals( this.min ) && box.max.equals( this.max ); - - } - - } ); + setRotationFromQuaternion: function ( q ) { - /** - * @author bhouston / http://clara.io - * @author mrdoob / http://mrdoob.com/ - */ + // assumes q is normalized - function Sphere( center, radius ) { + this.quaternion.copy( q ); - this.center = ( center !== undefined ) ? center : new Vector3(); - this.radius = ( radius !== undefined ) ? radius : 0; + }, - } + rotateOnAxis: function ( axis, angle ) { - Object.assign( Sphere.prototype, { + // rotate object on axis in object space + // axis is assumed to be normalized - set: function ( center, radius ) { + _q1.setFromAxisAngle( axis, angle ); - this.center.copy( center ); - this.radius = radius; + this.quaternion.multiply( _q1 ); return this; }, - setFromPoints: function () { - - var box = new Box3(); - - return function setFromPoints( points, optionalCenter ) { - - var center = this.center; + rotateOnWorldAxis: function ( axis, angle ) { - if ( optionalCenter !== undefined ) { + // rotate object on axis in world space + // axis is assumed to be normalized + // method assumes no rotated parent - center.copy( optionalCenter ); + _q1.setFromAxisAngle( axis, angle ); - } else { + this.quaternion.premultiply( _q1 ); - box.setFromPoints( points ).getCenter( center ); + return this; - } + }, - var maxRadiusSq = 0; + rotateX: function ( angle ) { - for ( var i = 0, il = points.length; i < il; i ++ ) { + return this.rotateOnAxis( _xAxis, angle ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + }, - } + rotateY: function ( angle ) { - this.radius = Math.sqrt( maxRadiusSq ); + return this.rotateOnAxis( _yAxis, angle ); - return this; + }, - }; + rotateZ: function ( angle ) { - }(), + return this.rotateOnAxis( _zAxis, angle ); - clone: function () { + }, - return new this.constructor().copy( this ); + translateOnAxis: function ( axis, distance ) { - }, + // translate object by distance along axis in object space + // axis is assumed to be normalized - copy: function ( sphere ) { + _v1$1.copy( axis ).applyQuaternion( this.quaternion ); - this.center.copy( sphere.center ); - this.radius = sphere.radius; + this.position.add( _v1$1.multiplyScalar( distance ) ); return this; }, - empty: function () { + translateX: function ( distance ) { - return ( this.radius <= 0 ); + return this.translateOnAxis( _xAxis, distance ); }, - containsPoint: function ( point ) { + translateY: function ( distance ) { - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + return this.translateOnAxis( _yAxis, distance ); }, - distanceToPoint: function ( point ) { + translateZ: function ( distance ) { - return ( point.distanceTo( this.center ) - this.radius ); + return this.translateOnAxis( _zAxis, distance ); }, - intersectsSphere: function ( sphere ) { - - var radiusSum = this.radius + sphere.radius; + localToWorld: function ( vector ) { - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + return vector.applyMatrix4( this.matrixWorld ); }, - intersectsBox: function ( box ) { + worldToLocal: function ( vector ) { - return box.intersectsSphere( this ); + return vector.applyMatrix4( _m1$1.getInverse( this.matrixWorld ) ); }, - intersectsPlane: function ( plane ) { - - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; + lookAt: function ( x, y, z ) { - }, + // This method does not support objects having non-uniformly-scaled parent(s) - clampPoint: function ( point, target ) { + if ( x.isVector3 ) { - var deltaLengthSq = this.center.distanceToSquared( point ); + _target.copy( x ); - if ( target === undefined ) { + } else { - console.warn( 'THREE.Sphere: .clampPoint() target is now required' ); - target = new Vector3(); + _target.set( x, y, z ); } - target.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { - - target.sub( this.center ).normalize(); - target.multiplyScalar( this.radius ).add( this.center ); + var parent = this.parent; - } + this.updateWorldMatrix( true, false ); - return target; + _position.setFromMatrixPosition( this.matrixWorld ); - }, + if ( this.isCamera || this.isLight ) { - getBoundingBox: function ( target ) { + _m1$1.lookAt( _position, _target, this.up ); - if ( target === undefined ) { + } else { - console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' ); - target = new Box3(); + _m1$1.lookAt( _target, _position, this.up ); } - target.set( this.center, this.center ); - target.expandByScalar( this.radius ); - - return target; - - }, + this.quaternion.setFromRotationMatrix( _m1$1 ); - applyMatrix4: function ( matrix ) { + if ( parent ) { - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); + _m1$1.extractRotation( parent.matrixWorld ); + _q1.setFromRotationMatrix( _m1$1 ); + this.quaternion.premultiply( _q1.inverse() ); - return this; + } }, - translate: function ( offset ) { - - this.center.add( offset ); + add: function ( object ) { - return this; + if ( arguments.length > 1 ) { - }, + for ( var i = 0; i < arguments.length; i ++ ) { - equals: function ( sphere ) { + this.add( arguments[ i ] ); - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + } - } + return this; - } ); + } - /** - * @author bhouston / http://clara.io - */ + if ( object === this ) { - function Plane( normal, constant ) { + console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); + return this; - // normal is assumed to be normalized + } - this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 ); - this.constant = ( constant !== undefined ) ? constant : 0; + if ( ( object && object.isObject3D ) ) { - } + if ( object.parent !== null ) { - Object.assign( Plane.prototype, { + object.parent.remove( object ); - set: function ( normal, constant ) { + } - this.normal.copy( normal ); - this.constant = constant; + object.parent = this; + this.children.push( object ); - return this; + object.dispatchEvent( _addedEvent ); - }, + } else { - setComponents: function ( x, y, z, w ) { + console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); - this.normal.set( x, y, z ); - this.constant = w; + } return this; }, - setFromNormalAndCoplanarPoint: function ( normal, point ) { - - this.normal.copy( normal ); - this.constant = - point.dot( this.normal ); - - return this; + remove: function ( object ) { - }, + if ( arguments.length > 1 ) { - setFromCoplanarPoints: function () { + for ( var i = 0; i < arguments.length; i ++ ) { - var v1 = new Vector3(); - var v2 = new Vector3(); + this.remove( arguments[ i ] ); - return function setFromCoplanarPoints( a, b, c ) { + } - var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); + return this; - // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? + } - this.setFromNormalAndCoplanarPoint( normal, a ); + var index = this.children.indexOf( object ); - return this; + if ( index !== - 1 ) { - }; + object.parent = null; + this.children.splice( index, 1 ); - }(), + object.dispatchEvent( _removedEvent ); - clone: function () { + } - return new this.constructor().copy( this ); + return this; }, - copy: function ( plane ) { + attach: function ( object ) { - this.normal.copy( plane.normal ); - this.constant = plane.constant; + // adds object as a child of this, while maintaining the object's world transform - return this; + this.updateWorldMatrix( true, false ); - }, + _m1$1.getInverse( this.matrixWorld ); - normalize: function () { + if ( object.parent !== null ) { - // Note: will lead to a divide by zero if the plane is invalid. + object.parent.updateWorldMatrix( true, false ); - var inverseNormalLength = 1.0 / this.normal.length(); - this.normal.multiplyScalar( inverseNormalLength ); - this.constant *= inverseNormalLength; + _m1$1.multiply( object.parent.matrixWorld ); - return this; + } - }, + object.applyMatrix4( _m1$1 ); - negate: function () { + object.updateWorldMatrix( false, false ); - this.constant *= - 1; - this.normal.negate(); + this.add( object ); return this; }, - distanceToPoint: function ( point ) { + getObjectById: function ( id ) { - return this.normal.dot( point ) + this.constant; + return this.getObjectByProperty( 'id', id ); }, - distanceToSphere: function ( sphere ) { + getObjectByName: function ( name ) { - return this.distanceToPoint( sphere.center ) - sphere.radius; + return this.getObjectByProperty( 'name', name ); }, - projectPoint: function ( point, target ) { - - if ( target === undefined ) { - - console.warn( 'THREE.Plane: .projectPoint() target is now required' ); - target = new Vector3(); - - } - - return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); - - }, + getObjectByProperty: function ( name, value ) { - intersectLine: function () { + if ( this[ name ] === value ) { return this; } - var v1 = new Vector3(); + for ( var i = 0, l = this.children.length; i < l; i ++ ) { - return function intersectLine( line, target ) { + var child = this.children[ i ]; + var object = child.getObjectByProperty( name, value ); - if ( target === undefined ) { + if ( object !== undefined ) { - console.warn( 'THREE.Plane: .intersectLine() target is now required' ); - target = new Vector3(); + return object; } - var direction = line.delta( v1 ); + } - var denominator = this.normal.dot( direction ); + return undefined; - if ( denominator === 0 ) { + }, - // line is coplanar, return origin - if ( this.distanceToPoint( line.start ) === 0 ) { + getWorldPosition: function ( target ) { - return target.copy( line.start ); + if ( target === undefined ) { - } + console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' ); + target = new Vector3(); - // Unsure if this is the correct method to handle this case. - return undefined; + } - } + this.updateMatrixWorld( true ); - var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; + return target.setFromMatrixPosition( this.matrixWorld ); - if ( t < 0 || t > 1 ) { + }, - return undefined; + getWorldQuaternion: function ( target ) { - } + if ( target === undefined ) { - return target.copy( direction ).multiplyScalar( t ).add( line.start ); + console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' ); + target = new Quaternion(); - }; + } - }(), + this.updateMatrixWorld( true ); - intersectsLine: function ( line ) { + this.matrixWorld.decompose( _position, target, _scale ); - // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. + return target; - var startSign = this.distanceToPoint( line.start ); - var endSign = this.distanceToPoint( line.end ); + }, - return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); + getWorldScale: function ( target ) { - }, + if ( target === undefined ) { - intersectsBox: function ( box ) { + console.warn( 'THREE.Object3D: .getWorldScale() target is now required' ); + target = new Vector3(); - return box.intersectsPlane( this ); + } - }, + this.updateMatrixWorld( true ); - intersectsSphere: function ( sphere ) { + this.matrixWorld.decompose( _position, _quaternion$2, target ); - return sphere.intersectsPlane( this ); + return target; }, - coplanarPoint: function ( target ) { + getWorldDirection: function ( target ) { if ( target === undefined ) { - console.warn( 'THREE.Plane: .coplanarPoint() target is now required' ); + console.warn( 'THREE.Object3D: .getWorldDirection() target is now required' ); target = new Vector3(); } - return target.copy( this.normal ).multiplyScalar( - this.constant ); - - }, - - applyMatrix4: function () { - - var v1 = new Vector3(); - var m1 = new Matrix3(); - - return function applyMatrix4( matrix, optionalNormalMatrix ) { + this.updateMatrixWorld( true ); - var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); + var e = this.matrixWorld.elements; - var referencePoint = this.coplanarPoint( v1 ).applyMatrix4( matrix ); + return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); - var normal = this.normal.applyMatrix3( normalMatrix ).normalize(); + }, - this.constant = - referencePoint.dot( normal ); + raycast: function () {}, - return this; + traverse: function ( callback ) { - }; + callback( this ); - }(), + var children = this.children; - translate: function ( offset ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - this.constant -= offset.dot( this.normal ); + children[ i ].traverse( callback ); - return this; + } }, - equals: function ( plane ) { - - return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); + traverseVisible: function ( callback ) { - } + if ( this.visible === false ) { return; } - } ); + callback( this ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author bhouston / http://clara.io - */ + var children = this.children; - function Frustum( p0, p1, p2, p3, p4, p5 ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - this.planes = [ + children[ i ].traverseVisible( callback ); - ( p0 !== undefined ) ? p0 : new Plane(), - ( p1 !== undefined ) ? p1 : new Plane(), - ( p2 !== undefined ) ? p2 : new Plane(), - ( p3 !== undefined ) ? p3 : new Plane(), - ( p4 !== undefined ) ? p4 : new Plane(), - ( p5 !== undefined ) ? p5 : new Plane() + } - ]; + }, - } + traverseAncestors: function ( callback ) { - Object.assign( Frustum.prototype, { + var parent = this.parent; - set: function ( p0, p1, p2, p3, p4, p5 ) { + if ( parent !== null ) { - var planes = this.planes; + callback( parent ); - planes[ 0 ].copy( p0 ); - planes[ 1 ].copy( p1 ); - planes[ 2 ].copy( p2 ); - planes[ 3 ].copy( p3 ); - planes[ 4 ].copy( p4 ); - planes[ 5 ].copy( p5 ); + parent.traverseAncestors( callback ); - return this; + } }, - clone: function () { + updateMatrix: function () { - return new this.constructor().copy( this ); + this.matrix.compose( this.position, this.quaternion, this.scale ); - }, + this.matrixWorldNeedsUpdate = true; - copy: function ( frustum ) { + }, - var planes = this.planes; + updateMatrixWorld: function ( force ) { - for ( var i = 0; i < 6; i ++ ) { + if ( this.matrixAutoUpdate ) { this.updateMatrix(); } - planes[ i ].copy( frustum.planes[ i ] ); + if ( this.matrixWorldNeedsUpdate || force ) { - } + if ( this.parent === null ) { - return this; + this.matrixWorld.copy( this.matrix ); - }, + } else { - setFromMatrix: function ( m ) { + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - var planes = this.planes; - var me = m.elements; - var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; - var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; - var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; - var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; + } - planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); - planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); - planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); - planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); - planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + this.matrixWorldNeedsUpdate = false; - return this; + force = true; - }, + } - intersectsObject: function () { + // update children - var sphere = new Sphere(); + var children = this.children; - return function intersectsObject( object ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - var geometry = object.geometry; + children[ i ].updateMatrixWorld( force ); - if ( geometry.boundingSphere === null ) - geometry.computeBoundingSphere(); + } - sphere.copy( geometry.boundingSphere ) - .applyMatrix4( object.matrixWorld ); + }, - return this.intersectsSphere( sphere ); + updateWorldMatrix: function ( updateParents, updateChildren ) { - }; + var parent = this.parent; - }(), + if ( updateParents === true && parent !== null ) { - intersectsSprite: function () { + parent.updateWorldMatrix( true, false ); - var sphere = new Sphere(); + } - return function intersectsSprite( sprite ) { + if ( this.matrixAutoUpdate ) { this.updateMatrix(); } - sphere.center.set( 0, 0, 0 ); - sphere.radius = 0.7071067811865476; - sphere.applyMatrix4( sprite.matrixWorld ); + if ( this.parent === null ) { - return this.intersectsSphere( sphere ); + this.matrixWorld.copy( this.matrix ); - }; + } else { - }(), + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - intersectsSphere: function ( sphere ) { + } - var planes = this.planes; - var center = sphere.center; - var negRadius = - sphere.radius; + // update children - for ( var i = 0; i < 6; i ++ ) { + if ( updateChildren === true ) { - var distance = planes[ i ].distanceToPoint( center ); + var children = this.children; - if ( distance < negRadius ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - return false; + children[ i ].updateWorldMatrix( false, true ); } } - return true; - }, - intersectsBox: function () { + toJSON: function ( meta ) { - var p = new Vector3(); + // meta is a string when called from JSON.stringify + var isRootObject = ( meta === undefined || typeof meta === 'string' ); - return function intersectsBox( box ) { + var output = {}; - var planes = this.planes; + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { - for ( var i = 0; i < 6; i ++ ) { + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {}, + shapes: {} + }; - var plane = planes[ i ]; + output.metadata = { + version: 4.5, + type: 'Object', + generator: 'Object3D.toJSON' + }; - // corner at max distance + } - p.x = plane.normal.x > 0 ? box.max.x : box.min.x; - p.y = plane.normal.y > 0 ? box.max.y : box.min.y; - p.z = plane.normal.z > 0 ? box.max.z : box.min.z; + // standard Object3D serialization - if ( plane.distanceToPoint( p ) < 0 ) { + var object = {}; - return false; + 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(); - return true; + if ( this.matrixAutoUpdate === false ) { object.matrixAutoUpdate = false; } - }; + // object specific properties - }(), + if ( this.isInstancedMesh ) { - containsPoint: function ( point ) { + object.type = 'InstancedMesh'; + object.count = this.count; + object.instanceMatrix = this.instanceMatrix.toJSON(); - var planes = this.planes; + } - for ( var i = 0; i < 6; i ++ ) { + // - if ( planes[ i ].distanceToPoint( point ) < 0 ) { + function serialize( library, element ) { - return false; + if ( library[ element.uuid ] === undefined ) { + + library[ element.uuid ] = element.toJSON( meta ); } + return element.uuid; + } - return true; + if ( this.isMesh || this.isLine || this.isPoints ) { - } + object.geometry = serialize( meta.geometries, this.geometry ); - } ); + var parameters = this.geometry.parameters; - var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif\n"; + if ( parameters !== undefined && parameters.shapes !== undefined ) { - var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif\n"; + var shapes = parameters.shapes; - var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif\n"; + if ( Array.isArray( shapes ) ) { - var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif\n"; + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; + var shape = shapes[ i ]; - var begin_vertex = "\nvec3 transformed = vec3( position );\n"; + serialize( meta.shapes, shape ); - var beginnormal_vertex = "\nvec3 objectNormal = vec3( normal );\n"; + } - var bsdfs = "float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat 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}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n"; + } else { - var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif\n"; + serialize( meta.shapes, shapes ); - var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t#endif\n#endif\n"; + } - var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif\n"; + } - var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvarying vec3 vViewPosition;\n#endif\n"; + } - var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n"; + if ( this.material !== undefined ) { - var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif"; + if ( Array.isArray( this.material ) ) { - var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif\n"; + var uuids = []; - var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif"; + for ( var i$1 = 0, l$1 = this.material.length; i$1 < l$1; i$1 ++ ) { - var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif"; + uuids.push( serialize( meta.materials, this.material[ i$1 ] ) ); - var common = "#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 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}\n"; + } - var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV( sampler2D envMap, vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif\n"; + object.material = uuids; - var defaultnormal_vertex = "vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n"; + } else { - var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif\n"; + object.material = serialize( meta.materials, this.material ); - var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif\n"; + } - var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif\n"; + } - var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif\n"; + // - var encodings_fragment = " gl_FragColor = linearToOutputTexel( gl_FragColor );\n"; + if ( this.children.length > 0 ) { - 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 = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}\n"; + object.children = []; - var envmap_fragment = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif\n"; + for ( var i$2 = 0; i$2 < this.children.length; i$2 ++ ) { - var envmap_pars_fragment = "#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif\n"; + object.children.push( this.children[ i$2 ].toJSON( meta ).object ); - var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif\n"; + } - var envmap_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif\n"; + } - var fog_vertex = "#ifdef USE_FOG\n\tfogDepth = -mvPosition.z;\n#endif\n"; + if ( isRootObject ) { - var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif\n"; + var geometries = extractFromCache( meta.geometries ); + var materials = extractFromCache( meta.materials ); + var textures = extractFromCache( meta.textures ); + var images = extractFromCache( meta.images ); + var shapes$1 = extractFromCache( meta.shapes ); - var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif\n"; + 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$1.length > 0 ) { output.shapes = shapes$1; } - var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif\n"; + } - var gradientmap_pars_fragment = "#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif\n"; + output.object = object; - var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif\n"; + return output; - var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache( cache ) { - var lights_lambert_vertex = "vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif\n"; + var values = []; + for ( var key in cache ) { - var lights_pars_begin = "uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t\tfloat shadowCameraNear;\n\t\tfloat shadowCameraFar;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D 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\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif\n"; + var data = cache[ key ]; + delete data.metadata; + values.push( data ); - var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent ));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif\n"; + } - var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;\n"; + return values; - var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)\n"; + } - var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif\n"; + }, - var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 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.specularRoughness;\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#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}\n"; + clone: function ( recursive ) { - var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearCoatRadiance = vec3( 0.0 );\n#endif\n"; + return new this.constructor().copy( this, recursive ); - var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), maxMipLevel );\n\t#ifndef STANDARD\n\t\tclearCoatRadiance += getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel );\n\t#endif\n#endif\n"; + }, - 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, clearCoatRadiance, geometry, material, reflectedLight );\n#endif\n"; + copy: function ( source, recursive ) { - var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; + if ( recursive === undefined ) { recursive = true; } - var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n#endif\n"; + this.name = source.name; - var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif\n"; + this.up.copy( source.up ); - var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\tgl_Position.z *= gl_Position.w;\n\t#endif\n#endif\n"; + this.position.copy( source.position ); + this.rotation.order = source.rotation.order; + this.quaternion.copy( source.quaternion ); + this.scale.copy( source.scale ); - var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif\n"; + this.matrix.copy( source.matrix ); + this.matrixWorld.copy( source.matrixWorld ); - var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n"; + this.matrixAutoUpdate = source.matrixAutoUpdate; + this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - var map_particle_fragment = "#ifdef USE_MAP\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n"; + this.layers.mask = source.layers.mask; + this.visible = source.visible; - var map_particle_pars_fragment = "#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif\n"; + this.castShadow = source.castShadow; + this.receiveShadow = source.receiveShadow; - var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif\n"; + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; - var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif\n"; + if ( recursive === true ) { - var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif"; + for ( var i = 0; i < source.children.length; i ++ ) { - var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif\n"; + var child = source.children[ i ]; + this.add( child.clone() ); - var normal_fragment_begin = "#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 * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n#endif\n"; + } - var normal_fragment_maps = "#ifdef USE_NORMALMAP\n\t#ifdef OBJECTSPACE_NORMALMAP\n\t\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\t#ifdef FLIP_SIDED\n\t\t\tnormal = - normal;\n\t\t#endif\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\tnormal = normalize( normalMatrix * normal );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif\n"; + } - var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\t#ifdef OBJECTSPACE_NORMALMAP\n\t\tuniform mat3 normalMatrix;\n\t#else\n\t\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\t\tvec2 st0 = dFdx( vUv.st );\n\t\t\tvec2 st1 = dFdy( vUv.st );\n\t\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\t\tvec3 N = normalize( surf_norm );\n\t\t\tmat3 tsn = mat3( S, T, N );\n\t\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\t\tmapN.xy *= normalScale;\n\t\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\treturn normalize( tsn * mapN );\n\t\t}\n\t#endif\n#endif\n"; + return this; - 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}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}\n"; + } - var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif\n"; + } ); - var project_vertex = "vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;\n"; + function Scene() { - var dithering_fragment = "#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif\n"; + Object3D.call( this ); - var dithering_pars_fragment = "#if defined( 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\n"; + this.type = 'Scene'; - var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif\n"; + this.background = null; + this.environment = null; + this.fog = null; - var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; + this.overrideMaterial = null; - var shadowmap_pars_fragment = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\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\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( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\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 )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif\n"; + this.autoUpdate = true; // checked by the renderer - var shadowmap_pars_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif\n"; + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif\n"; + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef - var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}\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 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\n"; + Scene.prototype = Object.assign( Object.create( Object3D.prototype ), { - 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\n"; + constructor: Scene, - var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif\n"; + isScene: true, - 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"; + copy: function ( source, recursive ) { - var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; + Object3D.prototype.copy.call( this, source, recursive ); - var tonemapping_fragment = "#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif\n"; + 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(); } - var tonemapping_pars_fragment = "#ifndef saturate\n\t#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\n"; + if ( source.overrideMaterial !== null ) { this.overrideMaterial = source.overrideMaterial.clone(); } - var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif"; + this.autoUpdate = source.autoUpdate; + this.matrixAutoUpdate = source.matrixAutoUpdate; - var uv_pars_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\n"; + return this; - var uv_vertex = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif"; + }, - var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; + toJSON: function ( meta ) { - var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif"; + var data = Object3D.prototype.toJSON.call( this, meta ); - var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif"; + if ( this.background !== null ) { data.object.background = this.background.toJSON( meta ); } + if ( this.environment !== null ) { data.object.environment = this.environment.toJSON( meta ); } + if ( this.fog !== null ) { data.object.fog = this.fog.toJSON(); } - var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif\n"; + return data; - var background_frag = "uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tgl_FragColor = texture2D( t2D, vUv );\n}\n"; + }, - var background_vert = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position, 1.0 );\n\tgl_Position.z = 1.0;\n}\n"; + dispose: function () { - var cube_frag = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tgl_FragColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor.a *= opacity;\n}\n"; + this.dispatchEvent( { type: 'dispose' } ); - 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}\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 \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\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}\n"; + } ); - var depth_vert = "#include \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}\n"; + var _points = [ + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3(), + new Vector3() + ]; - 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 \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}\n"; + var _vector$1 = new Vector3(); - 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}\n"; + var _box = new Box3(); - var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}\n"; + // triangle centered vertices - var equirect_vert = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}\n"; + var _v0 = new Vector3(); + var _v1$2 = new Vector3(); + var _v2 = new Vector3(); - 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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + // triangle edge vectors - var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}\n"; + var _f0 = new Vector3(); + var _f1 = new Vector3(); + var _f2 = new Vector3(); - 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 \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\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * 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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + var _center = new Vector3(); + var _extents = new Vector3(); + var _triangleNormal = new Vector3(); + var _testAxis = new Vector3(); - 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#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\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}\n"; + function Box3( min, max ) { - var meshlambert_frag = "uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \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\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity ); + this.max = ( max !== undefined ) ? max : new Vector3( - Infinity, - Infinity, - Infinity ); - var meshlambert_vert = "#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\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}\n"; + } - var meshmatcap_frag = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\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 \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\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\tvec4 matcapColor = texture2D( matcap, uv );\n\tmatcapColor = matcapTexelToLinear( matcapColor );\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; - var meshmatcap_vert = "#define MATCAP\nvarying vec3 vViewPosition;\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 \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\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\tvViewPosition = - mvPosition.xyz;\n}\n"; + Object.assign( Box3.prototype, { - 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 \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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + isBox3: true, - var meshphong_vert = "#define PHONG\nvarying vec3 vViewPosition;\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 \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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\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}\n"; + set: function ( min, max ) { - var meshphysical_frag = "#define PHYSICAL\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifndef STANDARD\n\tuniform float clearCoat;\n\tuniform float clearCoatRoughness;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \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\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + this.min.copy( min ); + this.max.copy( max ); - var meshphysical_vert = "#define PHYSICAL\nvarying vec3 vViewPosition;\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 \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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\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}\n"; + return this; - var normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}\n"; + }, - var normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || ( defined( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\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( USE_NORMALMAP ) && ! defined( OBJECTSPACE_NORMALMAP ) )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}\n"; + setFromArray: function ( array ) { - var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + var minX = + Infinity; + var minY = + Infinity; + var minZ = + Infinity; - 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 = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 );\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}\n"; + var maxX = - Infinity; + var maxY = - Infinity; + var maxZ = - Infinity; - 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}\n"; + for ( var i = 0, l = array.length; i < l; i += 3 ) { - var shadow_vert = "#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}\n"; + var x = array[ i ]; + var y = array[ i + 1 ]; + var z = array[ i + 2 ]; - var sprite_frag = "uniform vec3 diffuse;\nuniform float opacity;\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\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n}\n"; + if ( x < minX ) { minX = x; } + if ( y < minY ) { minY = y; } + if ( z < minZ ) { minZ = z; } - 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 = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 );\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}\n"; + if ( x > maxX ) { maxX = x; } + if ( y > maxY ) { maxY = y; } + if ( z > maxZ ) { maxZ = z; } - var ShaderChunk = { - alphamap_fragment: alphamap_fragment, - alphamap_pars_fragment: alphamap_pars_fragment, - alphatest_fragment: alphatest_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_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_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, - normalmap_pars_fragment: normalmap_pars_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, - 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, - meshphong_frag: meshphong_frag, - meshphong_vert: meshphong_vert, - meshphysical_frag: meshphysical_frag, - meshphysical_vert: meshphysical_vert, - normal_frag: normal_frag, - normal_vert: normal_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 - }; + this.min.set( minX, minY, minZ ); + this.max.set( maxX, maxY, maxZ ); - /** - * Uniform Utilities - */ + return this; - var UniformsUtils = { + }, - merge: function ( uniforms ) { + setFromBufferAttribute: function ( attribute ) { - var merged = {}; + var minX = + Infinity; + var minY = + Infinity; + var minZ = + Infinity; - for ( var u = 0; u < uniforms.length; u ++ ) { + var maxX = - Infinity; + var maxY = - Infinity; + var maxZ = - Infinity; - var tmp = this.clone( uniforms[ u ] ); + for ( var i = 0, l = attribute.count; i < l; i ++ ) { - for ( var p in tmp ) { + var x = attribute.getX( i ); + var y = attribute.getY( i ); + var z = attribute.getZ( i ); - merged[ p ] = tmp[ p ]; + 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; } } - return merged; - - }, + this.min.set( minX, minY, minZ ); + this.max.set( maxX, maxY, maxZ ); - clone: function ( uniforms_src ) { + return this; - var uniforms_dst = {}; + }, - for ( var u in uniforms_src ) { + setFromPoints: function ( points ) { - uniforms_dst[ u ] = {}; + this.makeEmpty(); - for ( var p in uniforms_src[ u ] ) { + for ( var i = 0, il = points.length; i < il; i ++ ) { - var parameter_src = uniforms_src[ u ][ p ]; + this.expandByPoint( points[ i ] ); - if ( parameter_src && ( parameter_src.isColor || - parameter_src.isMatrix3 || parameter_src.isMatrix4 || - parameter_src.isVector2 || parameter_src.isVector3 || parameter_src.isVector4 || - parameter_src.isTexture ) ) { + } - uniforms_dst[ u ][ p ] = parameter_src.clone(); + return this; - } else if ( Array.isArray( parameter_src ) ) { + }, - uniforms_dst[ u ][ p ] = parameter_src.slice(); + setFromCenterAndSize: function ( center, size ) { - } else { + var halfSize = _vector$1.copy( size ).multiplyScalar( 0.5 ); - uniforms_dst[ u ][ p ] = parameter_src; + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - } + return this; - } + }, - } + setFromObject: function ( object ) { - return uniforms_dst; + this.makeEmpty(); - } + return this.expandByObject( object ); - }; + }, - /** - * @author mrdoob / http://mrdoob.com/ - */ + clone: function () { - var 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 }; + return new this.constructor().copy( this ); - function Color( r, g, b ) { + }, - if ( g === undefined && b === undefined ) { + copy: function ( box ) { - // r is THREE.Color, hex or string - return this.set( r ); + this.min.copy( box.min ); + this.max.copy( box.max ); - } + return this; - return this.setRGB( r, g, b ); + }, - } + makeEmpty: function () { - Object.assign( Color.prototype, { + this.min.x = this.min.y = this.min.z = + Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; - isColor: true, + return this; - r: 1, g: 1, b: 1, + }, - set: function ( value ) { + isEmpty: function () { - if ( value && value.isColor ) { + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - this.copy( value ); + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - } else if ( typeof value === 'number' ) { + }, - this.setHex( value ); + getCenter: function ( target ) { - } else if ( typeof value === 'string' ) { + if ( target === undefined ) { - this.setStyle( value ); + console.warn( 'THREE.Box3: .getCenter() target is now required' ); + target = new Vector3(); } - return this; + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); }, - setScalar: function ( scalar ) { + getSize: function ( target ) { - this.r = scalar; - this.g = scalar; - this.b = scalar; + if ( target === undefined ) { - return this; + console.warn( 'THREE.Box3: .getSize() target is now required' ); + target = new Vector3(); - }, + } - setHex: function ( hex ) { + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); - hex = Math.floor( hex ); + }, - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; + expandByPoint: function ( point ) { + + this.min.min( point ); + this.max.max( point ); return this; }, - setRGB: function ( r, g, b ) { + expandByVector: function ( vector ) { - this.r = r; - this.g = g; - this.b = b; + this.min.sub( vector ); + this.max.add( vector ); return this; }, - setHSL: function () { + expandByScalar: function ( scalar ) { - function hue2rgb( p, q, t ) { + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - 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; + return this; - } + }, - return function setHSL( h, s, l ) { + expandByObject: function ( object ) { - // h,s,l ranges are in 0.0 - 1.0 - h = _Math.euclideanModulo( h, 1 ); - s = _Math.clamp( s, 0, 1 ); - l = _Math.clamp( l, 0, 1 ); + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms - if ( s === 0 ) { + object.updateWorldMatrix( false, false ); - this.r = this.g = this.b = l; + var geometry = object.geometry; - } else { + if ( geometry !== undefined ) { - var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - var q = ( 2 * l ) - p; + if ( geometry.boundingBox === null ) { - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); + geometry.computeBoundingBox(); } - return this; + _box.copy( geometry.boundingBox ); + _box.applyMatrix4( object.matrixWorld ); - }; + this.union( _box ); - }(), + } - setStyle: function ( style ) { + var children = object.children; - function handleAlpha( string ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - if ( string === undefined ) return; + this.expandByObject( children[ i ] ); - if ( parseFloat( string ) < 1 ) { + } - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); + return this; - } + }, - } + containsPoint: function ( 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; - var m; + }, - if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { + containsBox: function ( box ) { - // rgb / hsl + 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; - var color; - var name = m[ 1 ]; - var components = m[ 2 ]; + }, - switch ( name ) { + getParameter: function ( point, target ) { - case 'rgb': - case 'rgba': + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { + if ( target === undefined ) { - // 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; + console.warn( 'THREE.Box3: .getParameter() target is now required' ); + target = new Vector3(); - handleAlpha( color[ 5 ] ); + } - return this; + 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 ) + ); - } + }, - if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { + intersectsBox: function ( box ) { - // 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; + // 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; - handleAlpha( color[ 5 ] ); + }, - return this; + intersectsSphere: function ( sphere ) { - } + // Find the point on the AABB closest to the sphere center. + this.clampPoint( sphere.center, _vector$1 ); - break; + // If that point is inside the sphere, the AABB and sphere intersect. + return _vector$1.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); - case 'hsl': - case 'hsla': + }, - if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { + intersectsPlane: function ( plane ) { - // hsl(120,50%,50%) hsla(120,50%,50%,0.5) - var h = parseFloat( color[ 1 ] ) / 360; - var s = parseInt( color[ 2 ], 10 ) / 100; - var l = parseInt( color[ 3 ], 10 ) / 100; + // 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. - handleAlpha( color[ 5 ] ); + var min, max; - return this.setHSL( h, s, l ); + if ( plane.normal.x > 0 ) { - } + min = plane.normal.x * this.min.x; + max = plane.normal.x * this.max.x; - break; + } else { - } + min = plane.normal.x * this.max.x; + max = plane.normal.x * this.min.x; - } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { + } - // hex color + if ( plane.normal.y > 0 ) { - var hex = m[ 1 ]; - var size = hex.length; + min += plane.normal.y * this.min.y; + max += plane.normal.y * this.max.y; - if ( size === 3 ) { + } else { - // #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; + min += plane.normal.y * this.max.y; + max += plane.normal.y * this.min.y; - return this; + } - } else if ( size === 6 ) { + if ( plane.normal.z > 0 ) { - // #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; + min += plane.normal.z * this.min.z; + max += plane.normal.z * this.max.z; - return this; + } else { - } + min += plane.normal.z * this.max.z; + max += plane.normal.z * this.min.z; } - if ( style && style.length > 0 ) { + return ( min <= - plane.constant && max >= - plane.constant ); - // color keywords - var hex = ColorKeywords[ style ]; + }, - if ( hex !== undefined ) { + intersectsTriangle: function ( triangle ) { - // red - this.setHex( hex ); + if ( this.isEmpty() ) { - } else { + return false; - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); + } - } + // compute box center and extents + this.getCenter( _center ); + _extents.subVectors( this.max, _center ); + + // translate triangle to aabb origin + _v0.subVectors( triangle.a, _center ); + _v1$2.subVectors( triangle.b, _center ); + _v2.subVectors( triangle.c, _center ); + + // compute edge vectors for triangle + _f0.subVectors( _v1$2, _v0 ); + _f1.subVectors( _v2, _v1$2 ); + _f2.subVectors( _v0, _v2 ); + + // 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) + var 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, _v1$2, _v2, _extents ) ) { + + return false; } - return this; + // test 3 face normals from the aabb + axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; + if ( ! satForAxes( axes, _v0, _v1$2, _v2, _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, _v1$2, _v2, _extents ); }, - clone: function () { + clampPoint: function ( point, target ) { - return new this.constructor( this.r, this.g, this.b ); + if ( target === undefined ) { + + console.warn( 'THREE.Box3: .clampPoint() target is now required' ); + target = new Vector3(); + + } + + return target.copy( point ).clamp( this.min, this.max ); }, - copy: function ( color ) { + distanceToPoint: function ( point ) { - this.r = color.r; - this.g = color.g; - this.b = color.b; + var clampedPoint = _vector$1.copy( point ).clamp( this.min, this.max ); - return this; + return clampedPoint.sub( point ).length(); }, - copyGammaToLinear: function ( color, gammaFactor ) { + getBoundingSphere: function ( target ) { + + if ( target === undefined ) { - if ( gammaFactor === undefined ) gammaFactor = 2.0; + console.error( 'THREE.Box3: .getBoundingSphere() target is now required' ); + //target = new Sphere(); // removed to avoid cyclic dependency - this.r = Math.pow( color.r, gammaFactor ); - this.g = Math.pow( color.g, gammaFactor ); - this.b = Math.pow( color.b, gammaFactor ); + } - return this; + this.getCenter( target.center ); - }, + target.radius = this.getSize( _vector$1 ).length() * 0.5; - copyLinearToGamma: function ( color, gammaFactor ) { + return target; - if ( gammaFactor === undefined ) gammaFactor = 2.0; + }, - var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; + intersect: function ( box ) { - this.r = Math.pow( color.r, safeInverse ); - this.g = Math.pow( color.g, safeInverse ); - this.b = Math.pow( color.b, safeInverse ); + 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; }, - convertGammaToLinear: function ( gammaFactor ) { + union: function ( box ) { - this.copyGammaToLinear( this, gammaFactor ); + this.min.min( box.min ); + this.max.max( box.max ); return this; }, - convertLinearToGamma: function ( gammaFactor ) { + applyMatrix4: function ( matrix ) { - this.copyLinearToGamma( this, gammaFactor ); + // 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; }, - copySRGBToLinear: function () { + translate: function ( offset ) { - function SRGBToLinear( c ) { + this.min.add( offset ); + this.max.add( offset ); - return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); + return this; - } + }, - return function copySRGBToLinear( color ) { + equals: function ( box ) { - this.r = SRGBToLinear( color.r ); - this.g = SRGBToLinear( color.g ); - this.b = SRGBToLinear( color.b ); + return box.min.equals( this.min ) && box.max.equals( this.max ); - return this; + } - }; + } ); - }(), + function satForAxes( axes, v0, v1, v2, extents ) { - copyLinearToSRGB: function () { + for ( var i = 0, j = axes.length - 3; i <= j; i += 3 ) { - function LinearToSRGB( c ) { + _testAxis.fromArray( axes, i ); + // project the aabb onto the seperating axis + var 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 + var p0 = v0.dot( _testAxis ); + var p1 = v1.dot( _testAxis ); + var 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 ) { - return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; + // 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 function copyLinearToSRGB( color ) { - - this.r = LinearToSRGB( color.r ); - this.g = LinearToSRGB( color.g ); - this.b = LinearToSRGB( color.b ); + } - return this; + return true; - }; + } - }(), + var _box$1 = new Box3(); - convertSRGBToLinear: function () { + function Sphere( center, radius ) { - this.copySRGBToLinear( this ); + this.center = ( center !== undefined ) ? center : new Vector3(); + this.radius = ( radius !== undefined ) ? radius : - 1; - return this; + } - }, + Object.assign( Sphere.prototype, { - convertLinearToSRGB: function () { + set: function ( center, radius ) { - this.copyLinearToSRGB( this ); + this.center.copy( center ); + this.radius = radius; return this; }, - getHex: function () { + setFromPoints: function ( points, optionalCenter ) { - return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; + var center = this.center; - }, + if ( optionalCenter !== undefined ) { - getHexString: function () { + center.copy( optionalCenter ); - return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); + } else { - }, + _box$1.setFromPoints( points ).getCenter( center ); - getHSL: function ( target ) { + } - // h,s,l ranges are in 0.0 - 1.0 + var maxRadiusSq = 0; - if ( target === undefined ) { + for ( var i = 0, il = points.length; i < il; i ++ ) { - console.warn( 'THREE.Color: .getHSL() target is now required' ); - target = { h: 0, s: 0, l: 0 }; + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); } - var r = this.r, g = this.g, b = this.b; + this.radius = Math.sqrt( maxRadiusSq ); - var max = Math.max( r, g, b ); - var min = Math.min( r, g, b ); + return this; - var hue, saturation; - var lightness = ( min + max ) / 2.0; + }, - if ( min === max ) { + clone: function () { - hue = 0; - saturation = 0; + return new this.constructor().copy( this ); - } else { + }, - var delta = max - min; + copy: function ( sphere ) { - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + this.center.copy( sphere.center ); + this.radius = sphere.radius; - switch ( max ) { + return this; - 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; + }, - } + isEmpty: function () { - hue /= 6; + return ( this.radius < 0 ); - } + }, - target.h = hue; - target.s = saturation; - target.l = lightness; + makeEmpty: function () { - return target; + this.center.set( 0, 0, 0 ); + this.radius = - 1; + + return this; }, - getStyle: function () { + containsPoint: function ( point ) { - return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); }, - offsetHSL: function () { + distanceToPoint: function ( point ) { - var hsl = {}; + return ( point.distanceTo( this.center ) - this.radius ); - return function ( h, s, l ) { + }, - this.getHSL( hsl ); + intersectsSphere: function ( sphere ) { - hsl.h += h; hsl.s += s; hsl.l += l; + var radiusSum = this.radius + sphere.radius; - this.setHSL( hsl.h, hsl.s, hsl.l ); + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); - return this; + }, - }; + intersectsBox: function ( box ) { - }(), + return box.intersectsSphere( this ); - add: function ( color ) { + }, - this.r += color.r; - this.g += color.g; - this.b += color.b; + intersectsPlane: function ( plane ) { - return this; + return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; }, - addColors: function ( color1, color2 ) { + clampPoint: function ( point, target ) { - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; + var deltaLengthSq = this.center.distanceToSquared( point ); - return this; + if ( target === undefined ) { - }, + console.warn( 'THREE.Sphere: .clampPoint() target is now required' ); + target = new Vector3(); - addScalar: function ( s ) { + } - this.r += s; - this.g += s; - this.b += s; + target.copy( point ); - return this; + if ( deltaLengthSq > ( this.radius * this.radius ) ) { + + target.sub( this.center ).normalize(); + target.multiplyScalar( this.radius ).add( this.center ); + + } + + return target; }, - sub: function ( color ) { + getBoundingBox: function ( target ) { - 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 ); + if ( target === undefined ) { - return this; + console.warn( 'THREE.Sphere: .getBoundingBox() target is now required' ); + target = new Box3(); - }, + } - multiply: function ( color ) { + if ( this.isEmpty() ) { - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; + // Empty sphere produces empty bounding box + target.makeEmpty(); + return target; - return this; + } + + target.set( this.center, this.center ); + target.expandByScalar( this.radius ); + + return target; }, - multiplyScalar: function ( s ) { + applyMatrix4: function ( matrix ) { - this.r *= s; - this.g *= s; - this.b *= s; + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); return this; }, - lerp: function ( color, alpha ) { + translate: function ( offset ) { - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; + this.center.add( offset ); return this; }, - lerpHSL: function () { + equals: function ( sphere ) { + + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + + } - var hslA = { h: 0, s: 0, l: 0 }; - var hslB = { h: 0, s: 0, l: 0 }; + } ); - return function lerpHSL( color, alpha ) { + var _vector$2 = new Vector3(); + var _segCenter = new Vector3(); + var _segDir = new Vector3(); + var _diff = new Vector3(); - this.getHSL( hslA ); - color.getHSL( hslB ); + var _edge1 = new Vector3(); + var _edge2 = new Vector3(); + var _normal = new Vector3(); - var h = _Math.lerp( hslA.h, hslB.h, alpha ); - var s = _Math.lerp( hslA.s, hslB.s, alpha ); - var l = _Math.lerp( hslA.l, hslB.l, alpha ); + function Ray( origin, direction ) { - this.setHSL( h, s, l ); + this.origin = ( origin !== undefined ) ? origin : new Vector3(); + this.direction = ( direction !== undefined ) ? direction : new Vector3( 0, 0, - 1 ); - return this; + } - }; + Object.assign( Ray.prototype, { - }(), + set: function ( origin, direction ) { - equals: function ( c ) { + this.origin.copy( origin ); + this.direction.copy( direction ); - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + return this; }, - fromArray: function ( array, offset ) { + clone: function () { - if ( offset === undefined ) offset = 0; + return new this.constructor().copy( this ); - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; + }, + + copy: function ( ray ) { + + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); return this; }, - toArray: function ( array, offset ) { + at: function ( t, target ) { - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; + if ( target === undefined ) { - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; + console.warn( 'THREE.Ray: .at() target is now required' ); + target = new Vector3(); - return array; + } - }, + return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); - toJSON: function () { + }, - return this.getHex(); + lookAt: function ( v ) { - } + this.direction.copy( v ).sub( this.origin ).normalize(); - } ); + return this; - /** - * Uniforms library for shared webgl shaders - */ + }, - var UniformsLib = { + recast: function ( t ) { - common: { + this.origin.copy( this.at( t, _vector$2 ) ); - diffuse: { value: new Color( 0xeeeeee ) }, - opacity: { value: 1.0 }, + return this; - map: { value: null }, - uvTransform: { value: new Matrix3() }, + }, - alphaMap: { value: null }, + closestPointToPoint: function ( point, target ) { - }, + if ( target === undefined ) { - specularmap: { + console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' ); + target = new Vector3(); - specularMap: { value: null }, + } - }, + target.subVectors( point, this.origin ); - envmap: { + var directionDistance = target.dot( this.direction ); - envMap: { value: null }, - flipEnvMap: { value: - 1 }, - reflectivity: { value: 1.0 }, - refractionRatio: { value: 0.98 }, - maxMipLevel: { value: 0 } + if ( directionDistance < 0 ) { - }, + return target.copy( this.origin ); - aomap: { + } - aoMap: { value: null }, - aoMapIntensity: { value: 1 } + return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); }, - lightmap: { + distanceToPoint: function ( point ) { - lightMap: { value: null }, - lightMapIntensity: { value: 1 } + return Math.sqrt( this.distanceSqToPoint( point ) ); }, - emissivemap: { + distanceSqToPoint: function ( point ) { - emissiveMap: { value: null } + var directionDistance = _vector$2.subVectors( point, this.origin ).dot( this.direction ); - }, + // point behind the ray - bumpmap: { + if ( directionDistance < 0 ) { - bumpMap: { value: null }, - bumpScale: { value: 1 } + return this.origin.distanceToSquared( point ); - }, + } - normalmap: { + _vector$2.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); - normalMap: { value: null }, - normalScale: { value: new Vector2( 1, 1 ) } + return _vector$2.distanceToSquared( point ); }, - displacementmap: { + distanceSqToSegment: function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - displacementMap: { value: null }, - displacementScale: { value: 1 }, - displacementBias: { value: 0 } + // 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 ); - roughnessmap: { + var segExtent = v0.distanceTo( v1 ) * 0.5; + var a01 = - this.direction.dot( _segDir ); + var b0 = _diff.dot( this.direction ); + var b1 = - _diff.dot( _segDir ); + var c = _diff.lengthSq(); + var det = Math.abs( 1 - a01 * a01 ); + var s0, s1, sqrDist, extDet; - roughnessMap: { value: null } + if ( det > 0 ) { - }, + // The ray and segment are not parallel. - metalnessmap: { + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - metalnessMap: { value: null } + if ( s0 >= 0 ) { - }, + if ( s1 >= - extDet ) { - gradientmap: { + if ( s1 <= extDet ) { - gradientMap: { value: null } + // region 0 + // Minimum at interior points of ray and segment. - }, + var invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - fog: { + } else { - fogDensity: { value: 0.00025 }, - fogNear: { value: 1 }, - fogFar: { value: 2000 }, - fogColor: { value: new Color( 0xffffff ) } + // region 1 - }, + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - lights: { + } - ambientLightColor: { value: [] }, + } else { - directionalLights: { value: [], properties: { - direction: {}, - color: {}, + // region 5 - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - directionalShadowMap: { value: [] }, - directionalShadowMatrix: { value: [] }, + } - spotLights: { value: [], properties: { - color: {}, - position: {}, - direction: {}, - distance: {}, - coneCos: {}, - penumbraCos: {}, - decay: {}, + } else { - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {} - } }, + if ( s1 <= - extDet ) { - spotShadowMap: { value: [] }, - spotShadowMatrix: { value: [] }, + // region 4 - pointLights: { value: [], properties: { - color: {}, - position: {}, - decay: {}, - distance: {}, + 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; - shadow: {}, - shadowBias: {}, - shadowRadius: {}, - shadowMapSize: {}, - shadowCameraNear: {}, - shadowCameraFar: {} - } }, + } else if ( s1 <= extDet ) { - pointShadowMap: { value: [] }, - pointShadowMatrix: { value: [] }, + // region 3 - hemisphereLights: { value: [], properties: { - direction: {}, - skyColor: {}, - groundColor: {} - } }, + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src - rectAreaLights: { value: [], properties: { - color: {}, - position: {}, - width: {}, - height: {} - } } + } else { - }, + // region 2 - points: { + 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; - diffuse: { value: new Color( 0xeeeeee ) }, - opacity: { value: 1.0 }, - size: { value: 1.0 }, - scale: { value: 1.0 }, - map: { value: null }, - uvTransform: { value: new Matrix3() } + } - }, + } - sprite: { + } else { - diffuse: { value: new Color( 0xeeeeee ) }, - opacity: { value: 1.0 }, - center: { value: new Vector2( 0.5, 0.5 ) }, - rotation: { value: 0.0 }, - map: { value: null }, - uvTransform: { value: new Matrix3() } + // 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; - }; + } - /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - */ + if ( optionalPointOnRay ) { - var ShaderLib = { + optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); - basic: { + } - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.fog - ] ), + if ( optionalPointOnSegment ) { - vertexShader: ShaderChunk.meshbasic_vert, - fragmentShader: ShaderChunk.meshbasic_frag + optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter ); - }, + } - lambert: { + return sqrDist; - uniforms: UniformsUtils.merge( [ - 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 + intersectSphere: function ( sphere, target ) { - }, + _vector$2.subVectors( sphere.center, this.origin ); + var tca = _vector$2.dot( this.direction ); + var d2 = _vector$2.dot( _vector$2 ) - tca * tca; + var radius2 = sphere.radius * sphere.radius; - phong: { + if ( d2 > radius2 ) { return null; } - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.specularmap, - UniformsLib.envmap, - UniformsLib.aomap, - UniformsLib.lightmap, - UniformsLib.emissivemap, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.gradientmap, - UniformsLib.fog, - UniformsLib.lights, - { - emissive: { value: new Color( 0x000000 ) }, - specular: { value: new Color( 0x111111 ) }, - shininess: { value: 30 } - } - ] ), + var thc = Math.sqrt( radius2 - d2 ); - vertexShader: ShaderChunk.meshphong_vert, - fragmentShader: ShaderChunk.meshphong_frag + // t0 = first intersect point - entrance on front of sphere + var t0 = tca - thc; - }, + // t1 = second intersect point - exit point on back of sphere + var t1 = tca + thc; - standard: { + // test to see if both t0 and t1 are behind the ray - if so, return null + if ( t0 < 0 && t1 < 0 ) { return null; } - uniforms: UniformsUtils.merge( [ - 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: 0.5 }, - metalness: { value: 0.5 }, - envMapIntensity: { value: 1 } // temporary - } - ] ), + // 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 ); } - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, target ); }, - matcap: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - UniformsLib.fog, - { - matcap: { value: null } - } - ] ), + intersectsSphere: function ( sphere ) { - vertexShader: ShaderChunk.meshmatcap_vert, - fragmentShader: ShaderChunk.meshmatcap_frag + return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); }, - points: { + distanceToPlane: function ( plane ) { - uniforms: UniformsUtils.merge( [ - UniformsLib.points, - UniformsLib.fog - ] ), + var denominator = plane.normal.dot( this.direction ); - vertexShader: ShaderChunk.points_vert, - fragmentShader: ShaderChunk.points_frag + if ( denominator === 0 ) { - }, + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { - dashed: { + return 0; - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.fog, - { - scale: { value: 1 }, - dashSize: { value: 1 }, - totalSize: { value: 2 } } - ] ), - - vertexShader: ShaderChunk.linedashed_vert, - fragmentShader: ShaderChunk.linedashed_frag - - }, - - depth: { - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.displacementmap - ] ), + // Null is preferable to undefined since undefined means.... it is undefined - vertexShader: ShaderChunk.depth_vert, - fragmentShader: ShaderChunk.depth_frag + return null; - }, + } - normal: { + var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.bumpmap, - UniformsLib.normalmap, - UniformsLib.displacementmap, - { - opacity: { value: 1.0 } - } - ] ), + // Return if the ray never intersects the plane - vertexShader: ShaderChunk.normal_vert, - fragmentShader: ShaderChunk.normal_frag + return t >= 0 ? t : null; }, - sprite: { - - uniforms: UniformsUtils.merge( [ - UniformsLib.sprite, - UniformsLib.fog - ] ), + intersectPlane: function ( plane, target ) { - vertexShader: ShaderChunk.sprite_vert, - fragmentShader: ShaderChunk.sprite_frag + var t = this.distanceToPlane( plane ); - }, + if ( t === null ) { - background: { + return null; - uniforms: { - uvTransform: { value: new Matrix3() }, - t2D: { value: null }, - }, + } - vertexShader: ShaderChunk.background_vert, - fragmentShader: ShaderChunk.background_frag + return this.at( t, target ); }, - /* ------------------------------------------------------------------------- - // Cube map shader - ------------------------------------------------------------------------- */ - cube: { + intersectsPlane: function ( plane ) { - uniforms: { - tCube: { value: null }, - tFlip: { value: - 1 }, - opacity: { value: 1.0 } - }, + // check if the ray lies on the plane first - vertexShader: ShaderChunk.cube_vert, - fragmentShader: ShaderChunk.cube_frag + var distToPoint = plane.distanceToPoint( this.origin ); - }, + if ( distToPoint === 0 ) { - equirect: { + return true; - uniforms: { - tEquirect: { value: null }, - }, + } - vertexShader: ShaderChunk.equirect_vert, - fragmentShader: ShaderChunk.equirect_frag + var denominator = plane.normal.dot( this.direction ); - }, + if ( denominator * distToPoint < 0 ) { - distanceRGBA: { + return true; - uniforms: UniformsUtils.merge( [ - UniformsLib.common, - UniformsLib.displacementmap, - { - referencePosition: { value: new Vector3() }, - nearDistance: { value: 1 }, - farDistance: { value: 1000 } - } - ] ), + } - vertexShader: ShaderChunk.distanceRGBA_vert, - fragmentShader: ShaderChunk.distanceRGBA_frag + // ray origin is behind the plane (and is pointing behind it) + + return false; }, - shadow: { + intersectBox: function ( box, target ) { - uniforms: UniformsUtils.merge( [ - UniformsLib.lights, - UniformsLib.fog, - { - color: { value: new Color( 0x00000 ) }, - opacity: { value: 1.0 } - }, - ] ), + var tmin, tmax, tymin, tymax, tzmin, tzmax; - vertexShader: ShaderChunk.shadow_vert, - fragmentShader: ShaderChunk.shadow_frag + var invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; - } + var origin = this.origin; - }; + if ( invdirx >= 0 ) { - ShaderLib.physical = { + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; - uniforms: UniformsUtils.merge( [ - ShaderLib.standard.uniforms, - { - clearCoat: { value: 0 }, - clearCoatRoughness: { value: 0 } - } - ] ), + } else { - vertexShader: ShaderChunk.meshphysical_vert, - fragmentShader: ShaderChunk.meshphysical_frag + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; - }; + } - /** - * @author mrdoob / http://mrdoob.com/ - */ + if ( invdiry >= 0 ) { - function WebGLAnimation() { + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; - var context = null; - var isAnimating = false; - var animationLoop = null; + } else { - function onAnimationFrame( time, frame ) { + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; - if ( isAnimating === false ) return; + } - animationLoop( time, frame ); + if ( ( tmin > tymax ) || ( tymin > tmax ) ) { return null; } - context.requestAnimationFrame( onAnimationFrame ); + // 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; } - return { + if ( tymax < tmax || tmax !== tmax ) { tmax = tymax; } - start: function () { + if ( invdirz >= 0 ) { - if ( isAnimating === true ) return; - if ( animationLoop === null ) return; + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; - context.requestAnimationFrame( onAnimationFrame ); + } else { - isAnimating = true; + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; - }, + } - stop: function () { + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) { return null; } - isAnimating = false; + if ( tzmin > tmin || tmin !== tmin ) { tmin = tzmin; } - }, + if ( tzmax < tmax || tmax !== tmax ) { tmax = tzmax; } - setAnimationLoop: function ( callback ) { + //return point closest to the ray (positive side) - animationLoop = callback; + if ( tmax < 0 ) { return null; } - }, + return this.at( tmin >= 0 ? tmin : tmax, target ); - setContext: function ( value ) { + }, - context = value; + intersectsBox: function ( box ) { - } + return this.intersectBox( box, _vector$2 ) !== null; - }; + }, - } + intersectTriangle: function ( a, b, c, backfaceCulling, target ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + // Compute the offset origin, edges, and normal. - function WebGLAttributes( gl ) { + // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - var buffers = new WeakMap(); + _edge1.subVectors( b, a ); + _edge2.subVectors( c, a ); + _normal.crossVectors( _edge1, _edge2 ); - function createBuffer( attribute, bufferType ) { + // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, + // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by + // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) + // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) + // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) + var DdN = this.direction.dot( _normal ); + var sign; - var array = attribute.array; - var usage = attribute.dynamic ? 35048 : 35044; + if ( DdN > 0 ) { - var buffer = gl.createBuffer(); + if ( backfaceCulling ) { return null; } + sign = 1; - gl.bindBuffer( bufferType, buffer ); - gl.bufferData( bufferType, array, usage ); + } else if ( DdN < 0 ) { - attribute.onUploadCallback(); + sign = - 1; + DdN = - DdN; - var type = 5126; + } else { - if ( array instanceof Float32Array ) { + return null; - type = 5126; + } - } else if ( array instanceof Float64Array ) { + _diff.subVectors( this.origin, a ); + var DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); - console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' ); + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { - } else if ( array instanceof Uint16Array ) { + return null; - type = 5123; + } - } else if ( array instanceof Int16Array ) { + var DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); - type = 5122; + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { - } else if ( array instanceof Uint32Array ) { + return null; - type = 5125; + } - } else if ( array instanceof Int32Array ) { + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { - type = 5124; + return null; - } else if ( array instanceof Int8Array ) { + } - type = 5120; + // Line intersects triangle, check if ray does. + var QdN = - sign * _diff.dot( _normal ); - } else if ( array instanceof Uint8Array ) { + // t < 0, no intersection + if ( QdN < 0 ) { - type = 5121; + return null; } - return { - buffer: buffer, - type: type, - bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version - }; - - } + // Ray intersects triangle. + return this.at( QdN / DdN, target ); - function updateBuffer( buffer, attribute, bufferType ) { + }, - var array = attribute.array; - var updateRange = attribute.updateRange; + applyMatrix4: function ( matrix4 ) { - gl.bindBuffer( bufferType, buffer ); + this.origin.applyMatrix4( matrix4 ); + this.direction.transformDirection( matrix4 ); - if ( attribute.dynamic === false ) { + return this; - gl.bufferData( bufferType, array, 35044 ); + }, - } else if ( updateRange.count === - 1 ) { + equals: function ( ray ) { - // Not using update ranges + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - gl.bufferSubData( bufferType, 0, array ); + } - } else if ( updateRange.count === 0 ) { + } ); - console.error( 'THREE.WebGLObjects.updateBuffer: dynamic THREE.BufferAttribute marked as needsUpdate but updateRange.count is 0, ensure you are using set methods or updating manually.' ); + var _vector1 = new Vector3(); + var _vector2 = new Vector3(); + var _normalMatrix = new Matrix3(); - } else { + function Plane( normal, constant ) { - gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, - array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); + // normal is assumed to be normalized - updateRange.count = - 1; // reset range + this.normal = ( normal !== undefined ) ? normal : new Vector3( 1, 0, 0 ); + this.constant = ( constant !== undefined ) ? constant : 0; - } + } - } + Object.assign( Plane.prototype, { - // + isPlane: true, - function get( attribute ) { + set: function ( normal, constant ) { - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + this.normal.copy( normal ); + this.constant = constant; - return buffers.get( attribute ); + return this; - } + }, - function remove( attribute ) { + setComponents: function ( x, y, z, w ) { - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + this.normal.set( x, y, z ); + this.constant = w; - var data = buffers.get( attribute ); + return this; - if ( data ) { + }, - gl.deleteBuffer( data.buffer ); + setFromNormalAndCoplanarPoint: function ( normal, point ) { - buffers.delete( attribute ); + this.normal.copy( normal ); + this.constant = - point.dot( this.normal ); - } + return this; - } + }, - function update( attribute, bufferType ) { + setFromCoplanarPoints: function ( a, b, c ) { - if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; + var normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); - var data = buffers.get( attribute ); + // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? - if ( data === undefined ) { + this.setFromNormalAndCoplanarPoint( normal, a ); - buffers.set( attribute, createBuffer( attribute, bufferType ) ); + return this; - } else if ( data.version < attribute.version ) { + }, - updateBuffer( data.buffer, attribute, bufferType ); + clone: function () { - data.version = attribute.version; + return new this.constructor().copy( this ); - } + }, - } + copy: function ( plane ) { - return { + this.normal.copy( plane.normal ); + this.constant = plane.constant; - get: get, - remove: remove, - update: update + return this; - }; + }, - } + normalize: function () { - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + // Note: will lead to a divide by zero if the plane is invalid. - function Face3( a, b, c, normal, color, materialIndex ) { + var inverseNormalLength = 1.0 / this.normal.length(); + this.normal.multiplyScalar( inverseNormalLength ); + this.constant *= inverseNormalLength; - this.a = a; - this.b = b; - this.c = c; + return this; - this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3(); - this.vertexNormals = Array.isArray( normal ) ? normal : []; + }, - this.color = ( color && color.isColor ) ? color : new Color(); - this.vertexColors = Array.isArray( color ) ? color : []; + negate: function () { - this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + this.constant *= - 1; + this.normal.negate(); - } + return this; - Object.assign( Face3.prototype, { + }, - clone: function () { + distanceToPoint: function ( point ) { - return new this.constructor().copy( this ); + return this.normal.dot( point ) + this.constant; }, - copy: function ( source ) { + distanceToSphere: function ( sphere ) { - this.a = source.a; - this.b = source.b; - this.c = source.c; + return this.distanceToPoint( sphere.center ) - sphere.radius; - this.normal.copy( source.normal ); - this.color.copy( source.color ); + }, - this.materialIndex = source.materialIndex; + projectPoint: function ( point, target ) { - for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { + if ( target === undefined ) { - this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); + console.warn( 'THREE.Plane: .projectPoint() target is now required' ); + target = new Vector3(); } - for ( var i = 0, il = source.vertexColors.length; i < il; i ++ ) { - - this.vertexColors[ i ] = source.vertexColors[ i ].clone(); - - } + return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); - return this; + }, - } + intersectLine: function ( line, target ) { - } ); + if ( target === undefined ) { - /** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - * @author bhouston / http://clara.io - */ + console.warn( 'THREE.Plane: .intersectLine() target is now required' ); + target = new Vector3(); - function Euler( x, y, z, order ) { + } - this._x = x || 0; - this._y = y || 0; - this._z = z || 0; - this._order = order || Euler.DefaultOrder; + var direction = line.delta( _vector1 ); - } + var denominator = this.normal.dot( direction ); - Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; + if ( denominator === 0 ) { - Euler.DefaultOrder = 'XYZ'; + // line is coplanar, return origin + if ( this.distanceToPoint( line.start ) === 0 ) { - Object.defineProperties( Euler.prototype, { + return target.copy( line.start ); - x: { + } - get: function () { + // Unsure if this is the correct method to handle this case. + return undefined; - return this._x; + } - }, + var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; - set: function ( value ) { + if ( t < 0 || t > 1 ) { - this._x = value; - this.onChangeCallback(); + return undefined; } + return target.copy( direction ).multiplyScalar( t ).add( line.start ); + }, - y: { + intersectsLine: function ( line ) { - get: function () { + // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. - return this._y; + var startSign = this.distanceToPoint( line.start ); + var endSign = this.distanceToPoint( line.end ); - }, + return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); - set: function ( value ) { + }, - this._y = value; - this.onChangeCallback(); + intersectsBox: function ( box ) { - } + return box.intersectsPlane( this ); }, - z: { + intersectsSphere: function ( sphere ) { - get: function () { + return sphere.intersectsPlane( this ); - return this._z; + }, - }, + coplanarPoint: function ( target ) { - set: function ( value ) { + if ( target === undefined ) { - this._z = value; - this.onChangeCallback(); + console.warn( 'THREE.Plane: .coplanarPoint() target is now required' ); + target = new Vector3(); } + return target.copy( this.normal ).multiplyScalar( - this.constant ); + }, - order: { + applyMatrix4: function ( matrix, optionalNormalMatrix ) { - get: function () { + var normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); - return this._order; + var referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); - }, + var normal = this.normal.applyMatrix3( normalMatrix ).normalize(); - set: function ( value ) { + this.constant = - referencePoint.dot( normal ); - this._order = value; - this.onChangeCallback(); + return this; - } + }, - } - - } ); - - Object.assign( Euler.prototype, { - - isEuler: true, - - set: function ( x, y, z, order ) { - - this._x = x; - this._y = y; - this._z = z; - this._order = order || this._order; + translate: function ( offset ) { - this.onChangeCallback(); + this.constant -= offset.dot( this.normal ); return this; }, - clone: function () { + equals: function ( plane ) { - return new this.constructor( this._x, this._y, this._z, this._order ); + return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); - }, + } - copy: function ( euler ) { + } ); - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + var _v0$1 = new Vector3(); + var _v1$3 = new Vector3(); + var _v2$1 = new Vector3(); + var _v3 = new Vector3(); - this.onChangeCallback(); + var _vab = new Vector3(); + var _vac = new Vector3(); + var _vbc = new Vector3(); + var _vap = new Vector3(); + var _vbp = new Vector3(); + var _vcp = new Vector3(); - return this; + function Triangle( a, b, c ) { - }, + this.a = ( a !== undefined ) ? a : new Vector3(); + this.b = ( b !== undefined ) ? b : new Vector3(); + this.c = ( c !== undefined ) ? c : new Vector3(); - setFromRotationMatrix: function ( m, order, update ) { + } - var clamp = _Math.clamp; + Object.assign( Triangle, { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + getNormal: function ( a, b, c, target ) { - var te = m.elements; - var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; - var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; - var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + if ( target === undefined ) { - order = order || this._order; + console.warn( 'THREE.Triangle: .getNormal() target is now required' ); + target = new Vector3(); - if ( order === 'XYZ' ) { + } - this._y = Math.asin( clamp( m13, - 1, 1 ) ); + target.subVectors( c, b ); + _v0$1.subVectors( a, b ); + target.cross( _v0$1 ); - if ( Math.abs( m13 ) < 0.99999 ) { + var targetLengthSq = target.lengthSq(); + if ( targetLengthSq > 0 ) { - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); + return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); - } else { + } - this._x = Math.atan2( m32, m22 ); - this._z = 0; + return target.set( 0, 0, 0 ); - } + }, - } else if ( order === 'YXZ' ) { + // static/instance method to calculate barycentric coordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + getBarycoord: function ( point, a, b, c, target ) { - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + _v0$1.subVectors( c, a ); + _v1$3.subVectors( b, a ); + _v2$1.subVectors( point, a ); - if ( Math.abs( m23 ) < 0.99999 ) { + var dot00 = _v0$1.dot( _v0$1 ); + var dot01 = _v0$1.dot( _v1$3 ); + var dot02 = _v0$1.dot( _v2$1 ); + var dot11 = _v1$3.dot( _v1$3 ); + var dot12 = _v1$3.dot( _v2$1 ); - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); + var denom = ( dot00 * dot11 - dot01 * dot01 ); - } else { + if ( target === undefined ) { - this._y = Math.atan2( - m31, m11 ); - this._z = 0; + console.warn( 'THREE.Triangle: .getBarycoord() target is now required' ); + target = new Vector3(); - } + } - } else if ( order === 'ZXY' ) { + // collinear or singular triangle + if ( denom === 0 ) { - this._x = Math.asin( clamp( m32, - 1, 1 ) ); + // arbitrary location outside of triangle? + // not sure if this is the best idea, maybe should be returning undefined + return target.set( - 2, - 1, - 1 ); - if ( Math.abs( m32 ) < 0.99999 ) { + } - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); + var invDenom = 1 / denom; + var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - } else { + // barycentric coordinates must always sum to 1 + return target.set( 1 - u - v, v, u ); - this._y = 0; - this._z = Math.atan2( m21, m11 ); + }, - } + containsPoint: function ( point, a, b, c ) { - } else if ( order === 'ZYX' ) { + Triangle.getBarycoord( point, a, b, c, _v3 ); - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + return ( _v3.x >= 0 ) && ( _v3.y >= 0 ) && ( ( _v3.x + _v3.y ) <= 1 ); - if ( Math.abs( m31 ) < 0.99999 ) { + }, - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); + getUV: function ( point, p1, p2, p3, uv1, uv2, uv3, target ) { - } else { + this.getBarycoord( point, p1, p2, p3, _v3 ); - this._x = 0; - this._z = Math.atan2( - m12, m22 ); + target.set( 0, 0 ); + target.addScaledVector( uv1, _v3.x ); + target.addScaledVector( uv2, _v3.y ); + target.addScaledVector( uv3, _v3.z ); - } + return target; - } else if ( order === 'YZX' ) { + }, - this._z = Math.asin( clamp( m21, - 1, 1 ) ); + isFrontFacing: function ( a, b, c, direction ) { - if ( Math.abs( m21 ) < 0.99999 ) { + _v0$1.subVectors( c, b ); + _v1$3.subVectors( a, b ); - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); + // strictly front facing + return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; - } else { + } - this._x = 0; - this._y = Math.atan2( m13, m33 ); + } ); - } + Object.assign( Triangle.prototype, { + + set: function ( a, b, c ) { - } else if ( order === 'XZY' ) { + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + return this; - if ( Math.abs( m12 ) < 0.99999 ) { + }, - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); + setFromPointsAndIndices: function ( points, i0, i1, i2 ) { - } else { + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); - this._x = Math.atan2( - m23, m33 ); - this._y = 0; + return this; - } + }, - } else { + clone: function () { - console.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order ); + return new this.constructor().copy( this ); - } + }, - this._order = order; + copy: function ( triangle ) { - if ( update !== false ) this.onChangeCallback(); + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); return this; }, - setFromQuaternion: function () { + getArea: function () { - var matrix = new Matrix4(); + _v0$1.subVectors( this.c, this.b ); + _v1$3.subVectors( this.a, this.b ); - return function setFromQuaternion( q, order, update ) { + return _v0$1.cross( _v1$3 ).length() * 0.5; - matrix.makeRotationFromQuaternion( q ); + }, - return this.setFromRotationMatrix( matrix, order, update ); + getMidpoint: function ( target ) { - }; + if ( target === undefined ) { - }(), + console.warn( 'THREE.Triangle: .getMidpoint() target is now required' ); + target = new Vector3(); - setFromVector3: function ( v, order ) { + } - return this.set( v.x, v.y, v.z, order || this._order ); + return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); }, - reorder: function () { - - // WARNING: this discards revolution information -bhouston - - var q = new Quaternion(); + getNormal: function ( target ) { - return function reorder( newOrder ) { + return Triangle.getNormal( this.a, this.b, this.c, target ); - q.setFromEuler( this ); + }, - return this.setFromQuaternion( q, newOrder ); + getPlane: function ( target ) { - }; + if ( target === undefined ) { - }(), + console.warn( 'THREE.Triangle: .getPlane() target is now required' ); + target = new Plane(); - equals: function ( euler ) { + } - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + return target.setFromCoplanarPoints( this.a, this.b, this.c ); }, - fromArray: function ( array ) { + getBarycoord: function ( point, target ) { - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); + + }, - this.onChangeCallback(); + getUV: function ( point, uv1, uv2, uv3, target ) { - return this; + return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); }, - toArray: function ( array, offset ) { + containsPoint: function ( point ) { - if ( array === undefined ) array = []; - if ( offset === undefined ) offset = 0; + return Triangle.containsPoint( point, this.a, this.b, this.c ); - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; + }, - return array; + isFrontFacing: function ( direction ) { + + return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); }, - toVector3: function ( optionalResult ) { + intersectsBox: function ( box ) { - if ( optionalResult ) { + return box.intersectsTriangle( this ); - return optionalResult.set( this._x, this._y, this._z ); + }, - } else { + closestPointToPoint: function ( p, target ) { - return new Vector3( this._x, this._y, this._z ); + if ( target === undefined ) { - } + console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' ); + target = new Vector3(); - }, + } - onChange: function ( callback ) { + var a = this.a, b = this.b, c = this.c; + var v, w; - this.onChangeCallback = callback; + // 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. - return this; + _vab.subVectors( b, a ); + _vac.subVectors( c, a ); + _vap.subVectors( p, a ); + var d1 = _vab.dot( _vap ); + var d2 = _vac.dot( _vap ); + if ( d1 <= 0 && d2 <= 0 ) { - }, + // vertex region of A; barycentric coords (1, 0, 0) + return target.copy( a ); - onChangeCallback: function () {} + } - } ); + _vbp.subVectors( p, b ); + var d3 = _vab.dot( _vbp ); + var d4 = _vac.dot( _vbp ); + if ( d3 >= 0 && d4 <= d3 ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + // vertex region of B; barycentric coords (0, 1, 0) + return target.copy( b ); - function Layers() { + } - this.mask = 1 | 0; + var 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 ); - Object.assign( Layers.prototype, { + } - set: function ( channel ) { + _vcp.subVectors( p, c ); + var d5 = _vab.dot( _vcp ); + var d6 = _vac.dot( _vcp ); + if ( d6 >= 0 && d5 <= d6 ) { - this.mask = 1 << channel | 0; + // vertex region of C; barycentric coords (0, 0, 1) + return target.copy( c ); - }, + } - enable: function ( channel ) { + var vb = d5 * d2 - d1 * d6; + if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - this.mask |= 1 << channel | 0; + w = d2 / ( d2 - d6 ); + // edge region of AC; barycentric coords (1-w, 0, w) + return target.copy( a ).addScaledVector( _vac, w ); - }, + } - toggle: function ( channel ) { + var va = d3 * d6 - d5 * d4; + if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - this.mask ^= 1 << channel | 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 - }, + } - disable: function ( channel ) { + // face region + var denom = 1 / ( va + vb + vc ); + // u = va * denom + v = vb * denom; + w = vc * denom; - this.mask &= ~ ( 1 << channel | 0 ); + return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); }, - test: function ( layers ) { + equals: function ( triangle ) { - return ( this.mask & layers.mask ) !== 0; + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); } } ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author WestLangley / http://github.com/WestLangley - * @author elephantatwork / www.elephantatwork.ch - */ + var _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 }; - var object3DId = 0; + var _hslA = { h: 0, s: 0, l: 0 }; + var _hslB = { h: 0, s: 0, l: 0 }; - function Object3D() { + function Color( r, g, b ) { - Object.defineProperty( this, 'id', { value: object3DId ++ } ); + if ( g === undefined && b === undefined ) { - this.uuid = _Math.generateUUID(); + // r is THREE.Color, hex or string + return this.set( r ); - this.name = ''; - this.type = 'Object3D'; + } - this.parent = null; - this.children = []; + return this.setRGB( r, g, b ); - this.up = Object3D.DefaultUp.clone(); + } - var position = new Vector3(); - var rotation = new Euler(); - var quaternion = new Quaternion(); - var scale = new Vector3( 1, 1, 1 ); + function hue2rgb( p, q, t ) { - function onRotationChange() { + 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; - quaternion.setFromEuler( rotation, false ); + } - } + function SRGBToLinear( c ) { - function onQuaternionChange() { + return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); - rotation.setFromQuaternion( quaternion, undefined, false ); + } - } + function LinearToSRGB( c ) { - rotation.onChange( onRotationChange ); - quaternion.onChange( onQuaternionChange ); + return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; - 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(); + Object.assign( Color.prototype, { - this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; - this.matrixWorldNeedsUpdate = false; + isColor: true, - this.layers = new Layers(); - this.visible = true; + r: 1, g: 1, b: 1, - this.castShadow = false; - this.receiveShadow = false; + set: function ( value ) { - this.frustumCulled = true; - this.renderOrder = 0; + if ( value && value.isColor ) { - this.userData = {}; + this.copy( value ); - } + } else if ( typeof value === 'number' ) { - Object3D.DefaultUp = new Vector3( 0, 1, 0 ); - Object3D.DefaultMatrixAutoUpdate = true; + this.setHex( value ); - Object3D.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + } else if ( typeof value === 'string' ) { - constructor: Object3D, + this.setStyle( value ); - isObject3D: true, + } - onBeforeRender: function () {}, - onAfterRender: function () {}, + return this; - applyMatrix: function ( matrix ) { + }, - this.matrix.multiplyMatrices( matrix, this.matrix ); + setScalar: function ( scalar ) { - this.matrix.decompose( this.position, this.quaternion, this.scale ); + this.r = scalar; + this.g = scalar; + this.b = scalar; + + return this; }, - applyQuaternion: function ( q ) { + setHex: function ( hex ) { - this.quaternion.premultiply( q ); + hex = Math.floor( hex ); + + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; return this; }, - setRotationFromAxisAngle: function ( axis, angle ) { + setRGB: function ( r, g, b ) { - // assumes axis is normalized + this.r = r; + this.g = g; + this.b = b; - this.quaternion.setFromAxisAngle( axis, angle ); + return this; }, - setRotationFromEuler: function ( euler ) { - - this.quaternion.setFromEuler( euler, true ); + setHSL: function ( h, s, l ) { - }, + // h,s,l ranges are in 0.0 - 1.0 + h = MathUtils.euclideanModulo( h, 1 ); + s = MathUtils.clamp( s, 0, 1 ); + l = MathUtils.clamp( l, 0, 1 ); - setRotationFromMatrix: function ( m ) { + if ( s === 0 ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + this.r = this.g = this.b = l; - this.quaternion.setFromRotationMatrix( m ); + } else { - }, + var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + var q = ( 2 * l ) - p; - setRotationFromQuaternion: function ( q ) { + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); - // assumes q is normalized + } - this.quaternion.copy( q ); + return this; }, - rotateOnAxis: function () { - - // rotate object on axis in object space - // axis is assumed to be normalized + setStyle: function ( style ) { - var q1 = new Quaternion(); + function handleAlpha( string ) { - return function rotateOnAxis( axis, angle ) { + if ( string === undefined ) { return; } - q1.setFromAxisAngle( axis, angle ); + if ( parseFloat( string ) < 1 ) { - this.quaternion.multiply( q1 ); + console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); - return this; + } - }; + } - }(), - rotateOnWorldAxis: function () { + var m; - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent + if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) { - var q1 = new Quaternion(); + // rgb / hsl - return function rotateOnWorldAxis( axis, angle ) { + var color; + var name = m[ 1 ]; + var components = m[ 2 ]; - q1.setFromAxisAngle( axis, angle ); + switch ( name ) { - this.quaternion.premultiply( q1 ); + case 'rgb': + case 'rgba': - return this; + if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\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[ 5 ] ); - rotateX: function () { + return this; - var v1 = new Vector3( 1, 0, 0 ); + } - return function rotateX( angle ) { + if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { - return this.rotateOnAxis( v1, angle ); + // 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[ 5 ] ); - }(), + return this; - rotateY: function () { + } - var v1 = new Vector3( 0, 1, 0 ); + break; - return function rotateY( angle ) { + case 'hsl': + case 'hsla': - return this.rotateOnAxis( v1, angle ); + if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) { - }; + // hsl(120,50%,50%) hsla(120,50%,50%,0.5) + var h = parseFloat( color[ 1 ] ) / 360; + var s = parseInt( color[ 2 ], 10 ) / 100; + var l = parseInt( color[ 3 ], 10 ) / 100; - }(), + handleAlpha( color[ 5 ] ); - rotateZ: function () { + return this.setHSL( h, s, l ); - var v1 = new Vector3( 0, 0, 1 ); + } - return function rotateZ( angle ) { + break; - return this.rotateOnAxis( v1, angle ); + } - }; + } else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) { - }(), + // hex color - translateOnAxis: function () { + var hex = m[ 1 ]; + var size = hex.length; - // translate object by distance along axis in object space - // axis is assumed to be normalized + if ( size === 3 ) { - var v1 = new Vector3(); + // #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 function translateOnAxis( axis, distance ) { + return this; - v1.copy( axis ).applyQuaternion( this.quaternion ); + } else if ( size === 6 ) { - this.position.add( v1.multiplyScalar( distance ) ); + // #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; + return this; - }; + } - }(), + } - translateX: function () { + if ( style && style.length > 0 ) { - var v1 = new Vector3( 1, 0, 0 ); + return this.setColorName( style ); - return function translateX( distance ) { + } - return this.translateOnAxis( v1, distance ); + return this; - }; + }, - }(), + setColorName: function ( style ) { - translateY: function () { + // color keywords + var hex = _colorKeywords[ style ]; - var v1 = new Vector3( 0, 1, 0 ); + if ( hex !== undefined ) { - return function translateY( distance ) { + // red + this.setHex( hex ); - return this.translateOnAxis( v1, distance ); + } else { - }; + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); - }(), + } - translateZ: function () { + return this; - var v1 = new Vector3( 0, 0, 1 ); + }, - return function translateZ( distance ) { + clone: function () { - return this.translateOnAxis( v1, distance ); + return new this.constructor( this.r, this.g, this.b ); - }; + }, - }(), + copy: function ( color ) { - localToWorld: function ( vector ) { + this.r = color.r; + this.g = color.g; + this.b = color.b; - return vector.applyMatrix4( this.matrixWorld ); + return this; }, - worldToLocal: function () { + copyGammaToLinear: function ( color, gammaFactor ) { - var m1 = new Matrix4(); + if ( gammaFactor === undefined ) { gammaFactor = 2.0; } - return function worldToLocal( vector ) { + this.r = Math.pow( color.r, gammaFactor ); + this.g = Math.pow( color.g, gammaFactor ); + this.b = Math.pow( color.b, gammaFactor ); - return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); + return this; - }; + }, - }(), + copyLinearToGamma: function ( color, gammaFactor ) { - lookAt: function () { + if ( gammaFactor === undefined ) { gammaFactor = 2.0; } - // This method does not support objects having non-uniformly-scaled parent(s) + var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0; - var q1 = new Quaternion(); - var m1 = new Matrix4(); - var target = new Vector3(); - var position = new Vector3(); + this.r = Math.pow( color.r, safeInverse ); + this.g = Math.pow( color.g, safeInverse ); + this.b = Math.pow( color.b, safeInverse ); - return function lookAt( x, y, z ) { + return this; - if ( x.isVector3 ) { + }, - target.copy( x ); + convertGammaToLinear: function ( gammaFactor ) { - } else { + this.copyGammaToLinear( this, gammaFactor ); - target.set( x, y, z ); + return this; - } + }, - var parent = this.parent; + convertLinearToGamma: function ( gammaFactor ) { - this.updateWorldMatrix( true, false ); + this.copyLinearToGamma( this, gammaFactor ); - position.setFromMatrixPosition( this.matrixWorld ); + return this; - if ( this.isCamera ) { + }, - m1.lookAt( position, target, this.up ); + copySRGBToLinear: function ( color ) { - } else { + this.r = SRGBToLinear( color.r ); + this.g = SRGBToLinear( color.g ); + this.b = SRGBToLinear( color.b ); - m1.lookAt( target, position, this.up ); + return this; - } + }, - this.quaternion.setFromRotationMatrix( m1 ); + copyLinearToSRGB: function ( color ) { - if ( parent ) { + this.r = LinearToSRGB( color.r ); + this.g = LinearToSRGB( color.g ); + this.b = LinearToSRGB( color.b ); - m1.extractRotation( parent.matrixWorld ); - q1.setFromRotationMatrix( m1 ); - this.quaternion.premultiply( q1.inverse() ); + return this; - } + }, - }; + convertSRGBToLinear: function () { - }(), + this.copySRGBToLinear( this ); - add: function ( object ) { + return this; - if ( arguments.length > 1 ) { + }, - for ( var i = 0; i < arguments.length; i ++ ) { + convertLinearToSRGB: function () { - this.add( arguments[ i ] ); + this.copyLinearToSRGB( this ); - } + return this; - return this; + }, - } + getHex: function () { - if ( object === this ) { + return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; - console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object ); - return this; + }, - } + getHexString: function () { - if ( ( object && object.isObject3D ) ) { + return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); - if ( object.parent !== null ) { + }, - object.parent.remove( object ); + getHSL: function ( target ) { - } + // h,s,l ranges are in 0.0 - 1.0 - object.parent = this; - object.dispatchEvent( { type: 'added' } ); + if ( target === undefined ) { - this.children.push( object ); + console.warn( 'THREE.Color: .getHSL() target is now required' ); + target = { h: 0, s: 0, l: 0 }; - } else { + } - console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object ); + var r = this.r, g = this.g, b = this.b; - } + var max = Math.max( r, g, b ); + var min = Math.min( r, g, b ); - return this; + var hue, saturation; + var lightness = ( min + max ) / 2.0; - }, + if ( min === max ) { - remove: function ( object ) { + hue = 0; + saturation = 0; - if ( arguments.length > 1 ) { + } else { - for ( var i = 0; i < arguments.length; i ++ ) { + var delta = max - min; - this.remove( arguments[ i ] ); + 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; } - return this; + hue /= 6; } - var index = this.children.indexOf( object ); + target.h = hue; + target.s = saturation; + target.l = lightness; - if ( index !== - 1 ) { + return target; - object.parent = null; + }, - object.dispatchEvent( { type: 'removed' } ); + getStyle: function () { - this.children.splice( index, 1 ); + return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; - } + }, + + offsetHSL: function ( 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; }, - getObjectById: function ( id ) { + add: function ( color ) { - return this.getObjectByProperty( 'id', id ); + this.r += color.r; + this.g += color.g; + this.b += color.b; + + return this; }, - getObjectByName: function ( name ) { + addColors: function ( color1, color2 ) { - return this.getObjectByProperty( 'name', name ); + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; + + return this; }, - getObjectByProperty: function ( name, value ) { + addScalar: function ( s ) { + + this.r += s; + this.g += s; + this.b += s; - if ( this[ name ] === value ) return this; + return this; - for ( var i = 0, l = this.children.length; i < l; i ++ ) { + }, - var child = this.children[ i ]; - var object = child.getObjectByProperty( name, value ); + sub: function ( color ) { - if ( object !== undefined ) { + 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 object; + return this; - } + }, - } + multiply: function ( color ) { - return undefined; + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; }, - getWorldPosition: function ( target ) { + multiplyScalar: function ( s ) { - if ( target === undefined ) { + this.r *= s; + this.g *= s; + this.b *= s; - console.warn( 'THREE.Object3D: .getWorldPosition() target is now required' ); - target = new Vector3(); + return this; - } + }, - this.updateMatrixWorld( true ); + lerp: function ( color, alpha ) { - return target.setFromMatrixPosition( this.matrixWorld ); + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; - }, + return this; - getWorldQuaternion: function () { + }, - var position = new Vector3(); - var scale = new Vector3(); + lerpHSL: function ( color, alpha ) { - return function getWorldQuaternion( target ) { + this.getHSL( _hslA ); + color.getHSL( _hslB ); - if ( target === undefined ) { + var h = MathUtils.lerp( _hslA.h, _hslB.h, alpha ); + var s = MathUtils.lerp( _hslA.s, _hslB.s, alpha ); + var l = MathUtils.lerp( _hslA.l, _hslB.l, alpha ); - console.warn( 'THREE.Object3D: .getWorldQuaternion() target is now required' ); - target = new Quaternion(); + this.setHSL( h, s, l ); - } + return this; - this.updateMatrixWorld( true ); + }, - this.matrixWorld.decompose( position, target, scale ); + equals: function ( c ) { - return target; + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - }; + }, - }(), + fromArray: function ( array, offset ) { - getWorldScale: function () { + if ( offset === undefined ) { offset = 0; } - var position = new Vector3(); - var quaternion = new Quaternion(); + this.r = array[ offset ]; + this.g = array[ offset + 1 ]; + this.b = array[ offset + 2 ]; - return function getWorldScale( target ) { + return this; - if ( target === undefined ) { + }, - console.warn( 'THREE.Object3D: .getWorldScale() target is now required' ); - target = new Vector3(); + toArray: function ( array, offset ) { - } + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } - this.updateMatrixWorld( true ); + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; - this.matrixWorld.decompose( position, quaternion, target ); + return array; - return target; + }, - }; + fromBufferAttribute: function ( attribute, index ) { - }(), + this.r = attribute.getX( index ); + this.g = attribute.getY( index ); + this.b = attribute.getZ( index ); - getWorldDirection: function ( target ) { + if ( attribute.normalized === true ) { - if ( target === undefined ) { + // assuming Uint8Array - console.warn( 'THREE.Object3D: .getWorldDirection() target is now required' ); - target = new Vector3(); + this.r /= 255; + this.g /= 255; + this.b /= 255; } - this.updateMatrixWorld( true ); + return this; - var e = this.matrixWorld.elements; + }, - return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); + toJSON: function () { - }, + return this.getHex(); - raycast: function () {}, + } - traverse: function ( callback ) { + } ); - callback( this ); + Color.NAMES = _colorKeywords; - var children = this.children; + function Face3( a, b, c, normal, color, materialIndex ) { - for ( var i = 0, l = children.length; i < l; i ++ ) { + this.a = a; + this.b = b; + this.c = c; - children[ i ].traverse( callback ); + this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3(); + this.vertexNormals = Array.isArray( normal ) ? normal : []; - } + this.color = ( color && color.isColor ) ? color : new Color(); + this.vertexColors = Array.isArray( color ) ? color : []; + + this.materialIndex = materialIndex !== undefined ? materialIndex : 0; + + } + + Object.assign( Face3.prototype, { + + clone: function () { + + return new this.constructor().copy( this ); }, - traverseVisible: function ( callback ) { + copy: function ( source ) { - if ( this.visible === false ) return; + this.a = source.a; + this.b = source.b; + this.c = source.c; - callback( this ); + this.normal.copy( source.normal ); + this.color.copy( source.color ); - var children = this.children; + this.materialIndex = source.materialIndex; - for ( var i = 0, l = children.length; i < l; i ++ ) { + for ( var i = 0, il = source.vertexNormals.length; i < il; i ++ ) { - children[ i ].traverseVisible( callback ); + this.vertexNormals[ i ] = source.vertexNormals[ i ].clone(); } - }, + for ( var i$1 = 0, il$1 = source.vertexColors.length; i$1 < il$1; i$1 ++ ) { - traverseAncestors: function ( callback ) { + this.vertexColors[ i$1 ] = source.vertexColors[ i$1 ].clone(); - var parent = this.parent; + } - if ( parent !== null ) { + return this; - callback( parent ); + } - parent.traverseAncestors( callback ); + } ); - } + var materialId = 0; - }, + function Material() { - updateMatrix: function () { + Object.defineProperty( this, 'id', { value: materialId ++ } ); - this.matrix.compose( this.position, this.quaternion, this.scale ); + this.uuid = MathUtils.generateUUID(); - this.matrixWorldNeedsUpdate = true; + this.name = ''; + this.type = 'Material'; - }, + this.fog = true; - updateMatrixWorld: function ( force ) { + this.blending = NormalBlending; + this.side = FrontSide; + this.flatShading = false; + this.vertexColors = false; - if ( this.matrixAutoUpdate ) this.updateMatrix(); + this.opacity = 1; + this.transparent = false; - if ( this.matrixWorldNeedsUpdate || force ) { + this.blendSrc = SrcAlphaFactor; + this.blendDst = OneMinusSrcAlphaFactor; + this.blendEquation = AddEquation; + this.blendSrcAlpha = null; + this.blendDstAlpha = null; + this.blendEquationAlpha = null; - if ( this.parent === null ) { + this.depthFunc = LessEqualDepth; + this.depthTest = true; + this.depthWrite = true; - this.matrixWorld.copy( this.matrix ); + this.stencilWriteMask = 0xff; + this.stencilFunc = AlwaysStencilFunc; + this.stencilRef = 0; + this.stencilFuncMask = 0xff; + this.stencilFail = KeepStencilOp; + this.stencilZFail = KeepStencilOp; + this.stencilZPass = KeepStencilOp; + this.stencilWrite = false; - } else { + this.clippingPlanes = null; + this.clipIntersection = false; + this.clipShadows = false; - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + this.shadowSide = null; - } + this.colorWrite = true; - this.matrixWorldNeedsUpdate = false; + this.precision = null; // override the renderer's default precision for this material - force = true; + this.polygonOffset = false; + this.polygonOffsetFactor = 0; + this.polygonOffsetUnits = 0; - } + this.dithering = false; - // update children + this.alphaTest = 0; + this.premultipliedAlpha = false; - var children = this.children; + this.visible = true; - for ( var i = 0, l = children.length; i < l; i ++ ) { + this.toneMapped = true; - children[ i ].updateMatrixWorld( force ); + this.userData = {}; - } + this.version = 0; + + } + + Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + + constructor: Material, + + isMaterial: true, + + onBeforeCompile: function ( /* shaderobject, renderer */ ) {}, + + customProgramCacheKey: function () { + + return this.onBeforeCompile.toString(); }, - updateWorldMatrix: function ( updateParents, updateChildren ) { + setValues: function ( values ) { - var parent = this.parent; + if ( values === undefined ) { return; } - if ( updateParents === true && parent !== null ) { + for ( var key in values ) { - parent.updateWorldMatrix( true, false ); + var newValue = values[ key ]; - } + if ( newValue === undefined ) { - if ( this.matrixAutoUpdate ) this.updateMatrix(); + console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); + continue; - if ( this.parent === null ) { + } - this.matrixWorld.copy( this.matrix ); + // for backward compatability if shading is set in the constructor + if ( key === 'shading' ) { - } else { + console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); + this.flatShading = ( newValue === FlatShading ) ? true : false; + continue; - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + } - } + var currentValue = this[ key ]; - // update children + if ( currentValue === undefined ) { - if ( updateChildren === true ) { + console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); + continue; - var children = this.children; + } - for ( var i = 0, l = children.length; i < l; i ++ ) { + if ( currentValue && currentValue.isColor ) { - children[ i ].updateWorldMatrix( false, true ); + currentValue.set( newValue ); + + } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { + + currentValue.copy( newValue ); + + } else { + + this[ key ] = newValue; } @@ -8805,159 +8760,184 @@ toJSON: function ( meta ) { - // meta is a string when called from JSON.stringify - var isRootObject = ( meta === undefined || typeof meta === 'string' ); - - var output = {}; + var isRoot = ( meta === undefined || typeof meta === 'string' ); - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { + if ( isRoot ) { - // initialize meta obj meta = { - geometries: {}, - materials: {}, textures: {}, - images: {}, - shapes: {} - }; - - output.metadata = { - version: 4.5, - type: 'Object', - generator: 'Object3D.toJSON' + images: {} }; } - // standard Object3D serialization + var data = { + metadata: { + version: 4.5, + type: 'Material', + generator: 'Material.toJSON' + } + }; - var object = {}; + // standard Material serialization + data.uuid = this.uuid; + data.type = this.type; - object.uuid = this.uuid; - object.type = this.type; + if ( this.name !== '' ) { data.name = this.name; } - 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; + if ( this.color && this.color.isColor ) { data.color = this.color.getHex(); } - object.layers = this.layers.mask; - object.matrix = this.matrix.toArray(); + if ( this.roughness !== undefined ) { data.roughness = this.roughness; } + if ( this.metalness !== undefined ) { data.metalness = this.metalness; } - if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; + if ( this.sheen && this.sheen.isColor ) { data.sheen = this.sheen.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.shininess !== undefined ) { data.shininess = this.shininess; } + if ( this.clearcoat !== undefined ) { data.clearcoat = this.clearcoat; } + if ( this.clearcoatRoughness !== undefined ) { data.clearcoatRoughness = this.clearcoatRoughness; } - function serialize( library, element ) { + if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { - if ( library[ element.uuid ] === undefined ) { + data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; - library[ element.uuid ] = element.toJSON( meta ); + } - } + if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { - return element.uuid; + data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; } - if ( this.isMesh || this.isLine || this.isPoints ) { + if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { - object.geometry = serialize( meta.geometries, this.geometry ); + data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; + data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); - var parameters = this.geometry.parameters; + } - if ( parameters !== undefined && parameters.shapes !== undefined ) { + 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; } - var shapes = parameters.shapes; + if ( this.aoMap && this.aoMap.isTexture ) { - if ( Array.isArray( shapes ) ) { + data.aoMap = this.aoMap.toJSON( meta ).uuid; + data.aoMapIntensity = this.aoMapIntensity; - for ( var i = 0, l = shapes.length; i < l; i ++ ) { + } - var shape = shapes[ i ]; + if ( this.bumpMap && this.bumpMap.isTexture ) { - serialize( meta.shapes, shape ); + data.bumpMap = this.bumpMap.toJSON( meta ).uuid; + data.bumpScale = this.bumpScale; - } + } - } else { + if ( this.normalMap && this.normalMap.isTexture ) { - serialize( meta.shapes, shapes ); + 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.material !== undefined ) { + 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 ( Array.isArray( this.material ) ) { + 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; } - var uuids = []; + if ( this.envMap && this.envMap.isTexture ) { - for ( var i = 0, l = this.material.length; i < l; i ++ ) { + data.envMap = this.envMap.toJSON( meta ).uuid; + data.reflectivity = this.reflectivity; // Scale behind envMap + data.refractionRatio = this.refractionRatio; - uuids.push( serialize( meta.materials, this.material[ i ] ) ); + if ( this.combine !== undefined ) { data.combine = this.combine; } + if ( this.envMapIntensity !== undefined ) { data.envMapIntensity = this.envMapIntensity; } - } + } - object.material = uuids; + if ( this.gradientMap && this.gradientMap.isTexture ) { - } else { + data.gradientMap = this.gradientMap.toJSON( meta ).uuid; - object.material = serialize( meta.materials, this.material ); + } - } + if ( this.size !== undefined ) { data.size = this.size; } + if ( this.sizeAttenuation !== undefined ) { data.sizeAttenuation = this.sizeAttenuation; } - } + if ( this.blending !== NormalBlending ) { data.blending = this.blending; } + if ( this.flatShading === true ) { data.flatShading = this.flatShading; } + if ( this.side !== FrontSide ) { data.side = this.side; } + if ( this.vertexColors ) { data.vertexColors = true; } - // + if ( this.opacity < 1 ) { data.opacity = this.opacity; } + if ( this.transparent === true ) { data.transparent = this.transparent; } - if ( this.children.length > 0 ) { + data.depthFunc = this.depthFunc; + data.depthTest = this.depthTest; + data.depthWrite = this.depthWrite; - object.children = []; + 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; - for ( var i = 0; i < this.children.length; i ++ ) { + // rotation (SpriteMaterial) + if ( this.rotation && this.rotation !== 0 ) { data.rotation = this.rotation; } - object.children.push( this.children[ i ].toJSON( meta ).object ); + 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 ( isRootObject ) { + if ( this.alphaTest > 0 ) { data.alphaTest = this.alphaTest; } + if ( this.premultipliedAlpha === true ) { data.premultipliedAlpha = this.premultipliedAlpha; } - var geometries = extractFromCache( meta.geometries ); - var materials = extractFromCache( meta.materials ); - var textures = extractFromCache( meta.textures ); - var images = extractFromCache( meta.images ); - var shapes = extractFromCache( meta.shapes ); + 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 ( 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 ( this.morphTargets === true ) { data.morphTargets = true; } + if ( this.morphNormals === true ) { data.morphNormals = true; } + if ( this.skinning === true ) { data.skinning = true; } - } + if ( this.visible === false ) { data.visible = false; } - output.object = object; + if ( this.toneMapped === false ) { data.toneMapped = false; } - return output; + if ( JSON.stringify( this.userData ) !== '{}' ) { data.userData = this.userData; } + + // TODO: Copied from Object3D.toJSON - // extract data from the cache hash - // remove metadata on each item - // and return as array function extractFromCache( cache ) { var values = []; + for ( var key in cache ) { var data = cache[ key ]; @@ -8965,393 +8945,450 @@ values.push( data ); } + return values; } - }, + if ( isRoot ) { - clone: function ( recursive ) { + var textures = extractFromCache( meta.textures ); + var images = extractFromCache( meta.images ); - return new this.constructor().copy( this, recursive ); + if ( textures.length > 0 ) { data.textures = textures; } + if ( images.length > 0 ) { data.images = images; } + + } + + return data; }, - copy: function ( source, recursive ) { + clone: function () { + + return new this.constructor().copy( this ); + + }, - if ( recursive === undefined ) recursive = true; + copy: function ( source ) { this.name = source.name; - this.up.copy( source.up ); + this.fog = source.fog; - this.position.copy( source.position ); - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); + this.blending = source.blending; + this.side = source.side; + this.flatShading = source.flatShading; + this.vertexColors = source.vertexColors; - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); + this.opacity = source.opacity; + this.transparent = source.transparent; - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + 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.layers.mask = source.layers.mask; - this.visible = source.visible; + this.depthFunc = source.depthFunc; + this.depthTest = source.depthTest; + this.depthWrite = source.depthWrite; - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; + 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; - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; + var srcPlanes = source.clippingPlanes; + var dstPlanes = null; - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + if ( srcPlanes !== null ) { - if ( recursive === true ) { + var n = srcPlanes.length; + dstPlanes = new Array( n ); - for ( var i = 0; i < source.children.length; i ++ ) { + for ( var i = 0; i !== n; ++ i ) { - var child = source.children[ i ]; - this.add( child.clone() ); + dstPlanes[ i ] = srcPlanes[ i ].clone(); } } - return this; + this.clippingPlanes = dstPlanes; + this.clipIntersection = source.clipIntersection; + this.clipShadows = source.clipShadows; - } + this.shadowSide = source.shadowSide; - } ); + this.colorWrite = source.colorWrite; - /** - * @author mrdoob / http://mrdoob.com/ - * @author kile / http://kile.stravaganza.org/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author bhouston / http://clara.io - */ + this.precision = source.precision; - var geometryId = 0; // Geometry uses even numbers as Id + this.polygonOffset = source.polygonOffset; + this.polygonOffsetFactor = source.polygonOffsetFactor; + this.polygonOffsetUnits = source.polygonOffsetUnits; - function Geometry() { + this.dithering = source.dithering; - Object.defineProperty( this, 'id', { value: geometryId += 2 } ); + this.alphaTest = source.alphaTest; + this.premultipliedAlpha = source.premultipliedAlpha; - this.uuid = _Math.generateUUID(); + this.visible = source.visible; - this.name = ''; - this.type = 'Geometry'; + this.toneMapped = source.toneMapped; - this.vertices = []; - this.colors = []; - this.faces = []; - this.faceVertexUvs = [[]]; + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - this.morphTargets = []; - this.morphNormals = []; + return this; - this.skinWeights = []; - this.skinIndices = []; + }, - this.lineDistances = []; + dispose: function () { - this.boundingBox = null; - this.boundingSphere = null; + this.dispatchEvent( { type: 'dispose' } ); - // update flags + } - this.elementsNeedUpdate = false; - this.verticesNeedUpdate = false; - this.uvsNeedUpdate = false; - this.normalsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.lineDistancesNeedUpdate = false; - this.groupsNeedUpdate = false; + } ); - } + Object.defineProperty( Material.prototype, 'needsUpdate', { - Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + set: function ( value ) { - constructor: Geometry, + if ( value === true ) { this.version ++; } - isGeometry: true, + } - applyMatrix: function ( matrix ) { + } ); - var normalMatrix = new Matrix3().getNormalMatrix( matrix ); + /** + * 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: , + * + * skinning: , + * morphTargets: + * } + */ - for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { + function MeshBasicMaterial( parameters ) { - var vertex = this.vertices[ i ]; - vertex.applyMatrix4( matrix ); + Material.call( this ); - } + this.type = 'MeshBasicMaterial'; - for ( var i = 0, il = this.faces.length; i < il; i ++ ) { + this.color = new Color( 0xffffff ); // emissive - var face = this.faces[ i ]; - face.normal.applyMatrix3( normalMatrix ).normalize(); + this.map = null; - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + this.lightMap = null; + this.lightMapIntensity = 1.0; - face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); + this.aoMap = null; + this.aoMapIntensity = 1.0; - } + this.specularMap = null; - } + this.alphaMap = null; - if ( this.boundingBox !== null ) { + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - this.computeBoundingBox(); + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - } + this.skinning = false; + this.morphTargets = false; - if ( this.boundingSphere !== null ) { + this.setValues( parameters ); - this.computeBoundingSphere(); + } - } + MeshBasicMaterial.prototype = Object.create( Material.prototype ); + MeshBasicMaterial.prototype.constructor = MeshBasicMaterial; - this.verticesNeedUpdate = true; - this.normalsNeedUpdate = true; + MeshBasicMaterial.prototype.isMeshBasicMaterial = true; - return this; + MeshBasicMaterial.prototype.copy = function ( source ) { - }, + Material.prototype.copy.call( this, source ); - rotateX: function () { + this.color.copy( source.color ); - // rotate geometry around world x-axis + this.map = source.map; - var m1 = new Matrix4(); + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - return function rotateX( angle ) { + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - m1.makeRotationX( angle ); + this.specularMap = source.specularMap; - this.applyMatrix( m1 ); + this.alphaMap = source.alphaMap; - return this; + 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.skinning = source.skinning; + this.morphTargets = source.morphTargets; - rotateY: function () { + return this; - // rotate geometry around world y-axis + }; - var m1 = new Matrix4(); + var _vector$3 = new Vector3(); + var _vector2$1 = new Vector2(); - return function rotateY( angle ) { + function BufferAttribute( array, itemSize, normalized ) { - m1.makeRotationY( angle ); + if ( Array.isArray( array ) ) { - this.applyMatrix( m1 ); + throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); - return this; + } - }; + this.name = ''; - }(), + this.array = array; + this.itemSize = itemSize; + this.count = array !== undefined ? array.length / itemSize : 0; + this.normalized = normalized === true; - rotateZ: function () { + this.usage = StaticDrawUsage; + this.updateRange = { offset: 0, count: - 1 }; - // rotate geometry around world z-axis + this.version = 0; - var m1 = new Matrix4(); + } - return function rotateZ( angle ) { + Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', { - m1.makeRotationZ( angle ); + set: function ( value ) { - this.applyMatrix( m1 ); + if ( value === true ) { this.version ++; } - return this; + } - }; + } ); - }(), + Object.assign( BufferAttribute.prototype, { - translate: function () { + isBufferAttribute: true, - // translate geometry + onUploadCallback: function () {}, - var m1 = new Matrix4(); + setUsage: function ( value ) { - return function translate( x, y, z ) { + this.usage = value; - m1.makeTranslation( x, y, z ); + return this; - this.applyMatrix( m1 ); + }, - return this; + copy: function ( 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; - scale: function () { + return this; - // scale geometry + }, - var m1 = new Matrix4(); + copyAt: function ( index1, attribute, index2 ) { - return function scale( x, y, z ) { + index1 *= this.itemSize; + index2 *= attribute.itemSize; - m1.makeScale( x, y, z ); + for ( var i = 0, l = this.itemSize; i < l; i ++ ) { - this.applyMatrix( m1 ); + this.array[ index1 + i ] = attribute.array[ index2 + i ]; - return this; + } - }; + return this; - }(), + }, - lookAt: function () { + copyArray: function ( array ) { - var obj = new Object3D(); + this.array.set( array ); - return function lookAt( vector ) { + return this; - obj.lookAt( vector ); + }, - obj.updateMatrix(); + copyColorsArray: function ( colors ) { - this.applyMatrix( obj.matrix ); + var array = this.array; + var offset = 0; - }; + for ( var i = 0, l = colors.length; i < l; i ++ ) { - }(), + var color = colors[ i ]; - fromBufferGeometry: function ( geometry ) { + if ( color === undefined ) { - var scope = this; + console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); + color = new Color(); - var indices = geometry.index !== null ? geometry.index.array : undefined; - var attributes = geometry.attributes; + } - var positions = attributes.position.array; - var normals = attributes.normal !== undefined ? attributes.normal.array : undefined; - var colors = attributes.color !== undefined ? attributes.color.array : undefined; - var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined; - var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined; + array[ offset ++ ] = color.r; + array[ offset ++ ] = color.g; + array[ offset ++ ] = color.b; - if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = []; + } - for ( var i = 0, j = 0; i < positions.length; i += 3, j += 2 ) { + return this; - scope.vertices.push( new Vector3().fromArray( positions, i ) ); + }, - if ( colors !== undefined ) { + copyVector2sArray: function ( vectors ) { - scope.colors.push( new Color().fromArray( colors, i ) ); + var array = this.array; + var offset = 0; - } + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - } + var vector = vectors[ i ]; - function addFace( a, b, c, materialIndex ) { + if ( vector === undefined ) { - var vertexColors = ( colors === undefined ) ? [] : [ - scope.colors[ a ].clone(), - scope.colors[ b ].clone(), - scope.colors[ c ].clone() ]; + console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); + vector = new Vector2(); - var vertexNormals = ( normals === undefined ) ? [] : [ - new Vector3().fromArray( normals, a * 3 ), - new Vector3().fromArray( normals, b * 3 ), - new Vector3().fromArray( normals, c * 3 ) - ]; + } - var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex ); + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; - scope.faces.push( face ); + } - if ( uvs !== undefined ) { + return this; - scope.faceVertexUvs[ 0 ].push( [ - new Vector2().fromArray( uvs, a * 2 ), - new Vector2().fromArray( uvs, b * 2 ), - new Vector2().fromArray( uvs, c * 2 ) - ] ); + }, - } + copyVector3sArray: function ( vectors ) { - if ( uvs2 !== undefined ) { + var array = this.array; + var offset = 0; - scope.faceVertexUvs[ 1 ].push( [ - new Vector2().fromArray( uvs2, a * 2 ), - new Vector2().fromArray( uvs2, b * 2 ), - new Vector2().fromArray( uvs2, c * 2 ) - ] ); + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - } + var vector = vectors[ i ]; - } + if ( vector === undefined ) { - var groups = geometry.groups; + console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); + vector = new Vector3(); - if ( groups.length > 0 ) { + } - for ( var i = 0; i < groups.length; i ++ ) { + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + array[ offset ++ ] = vector.z; - var group = groups[ i ]; + } - var start = group.start; - var count = group.count; + return this; - for ( var j = start, jl = start + count; j < jl; j += 3 ) { + }, - if ( indices !== undefined ) { + copyVector4sArray: function ( vectors ) { - addFace( indices[ j ], indices[ j + 1 ], indices[ j + 2 ], group.materialIndex ); + var array = this.array; + var offset = 0; - } else { + for ( var i = 0, l = vectors.length; i < l; i ++ ) { - addFace( j, j + 1, j + 2, group.materialIndex ); + var vector = vectors[ i ]; - } + if ( vector === undefined ) { - } + console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); + vector = new Vector4(); } - } else { + array[ offset ++ ] = vector.x; + array[ offset ++ ] = vector.y; + array[ offset ++ ] = vector.z; + array[ offset ++ ] = vector.w; - if ( indices !== undefined ) { + } - for ( var i = 0; i < indices.length; i += 3 ) { + return this; - addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); + }, - } + applyMatrix3: function ( m ) { - } else { + if ( this.itemSize === 2 ) { - for ( var i = 0; i < positions.length / 3; i += 3 ) { + for ( var i = 0, l = this.count; i < l; i ++ ) { - addFace( i, i + 1, i + 2 ); + _vector2$1.fromBufferAttribute( this, i ); + _vector2$1.applyMatrix3( m ); - } + this.setXY( i, _vector2$1.x, _vector2$1.y ); } - } - - this.computeFaceNormals(); - - if ( geometry.boundingBox !== null ) { + } else if ( this.itemSize === 3 ) { - this.boundingBox = geometry.boundingBox.clone(); + for ( var i$1 = 0, l$1 = this.count; i$1 < l$1; i$1 ++ ) { - } + _vector$3.fromBufferAttribute( this, i$1 ); + _vector$3.applyMatrix3( m ); - if ( geometry.boundingSphere !== null ) { + this.setXYZ( i$1, _vector$3.x, _vector$3.y, _vector$3.z ); - this.boundingSphere = geometry.boundingSphere.clone(); + } } @@ -9359,3585 +9396,3581 @@ }, - center: function () { - - var offset = new Vector3(); + applyMatrix4: function ( m ) { - return function center() { + for ( var i = 0, l = this.count; i < l; i ++ ) { - this.computeBoundingBox(); + _vector$3.x = this.getX( i ); + _vector$3.y = this.getY( i ); + _vector$3.z = this.getZ( i ); - this.boundingBox.getCenter( offset ).negate(); + _vector$3.applyMatrix4( m ); - this.translate( offset.x, offset.y, offset.z ); + this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z ); - return this; + } - }; + return this; - }(), + }, - normalize: function () { + applyNormalMatrix: function ( m ) { - this.computeBoundingSphere(); + for ( var i = 0, l = this.count; i < l; i ++ ) { - var center = this.boundingSphere.center; - var radius = this.boundingSphere.radius; + _vector$3.x = this.getX( i ); + _vector$3.y = this.getY( i ); + _vector$3.z = this.getZ( i ); - var s = radius === 0 ? 1 : 1.0 / radius; + _vector$3.applyNormalMatrix( m ); - var matrix = new Matrix4(); - matrix.set( - s, 0, 0, - s * center.x, - 0, s, 0, - s * center.y, - 0, 0, s, - s * center.z, - 0, 0, 0, 1 - ); + this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z ); - this.applyMatrix( matrix ); + } return this; }, - computeFaceNormals: function () { - - var cb = new Vector3(), ab = new Vector3(); - - for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - - var face = this.faces[ f ]; + transformDirection: function ( m ) { - var vA = this.vertices[ face.a ]; - var vB = this.vertices[ face.b ]; - var vC = this.vertices[ face.c ]; + for ( var i = 0, l = this.count; i < l; i ++ ) { - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); + _vector$3.x = this.getX( i ); + _vector$3.y = this.getY( i ); + _vector$3.z = this.getZ( i ); - cb.normalize(); + _vector$3.transformDirection( m ); - face.normal.copy( cb ); + this.setXYZ( i, _vector$3.x, _vector$3.y, _vector$3.z ); } - }, + return this; - computeVertexNormals: function ( areaWeighted ) { + }, - if ( areaWeighted === undefined ) areaWeighted = true; + set: function ( value, offset ) { - var v, vl, f, fl, face, vertices; + if ( offset === undefined ) { offset = 0; } - vertices = new Array( this.vertices.length ); + this.array.set( value, offset ); - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + return this; - vertices[ v ] = new Vector3(); + }, - } + getX: function ( index ) { - if ( areaWeighted ) { + return this.array[ index * this.itemSize ]; - // vertex normals weighted by triangle areas - // http://www.iquilezles.org/www/articles/normals/normals.htm + }, - var vA, vB, vC; - var cb = new Vector3(), ab = new Vector3(); + setX: function ( index, x ) { - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + this.array[ index * this.itemSize ] = x; - face = this.faces[ f ]; + return this; - vA = this.vertices[ face.a ]; - vB = this.vertices[ face.b ]; - vC = this.vertices[ face.c ]; + }, - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ); + getY: function ( index ) { - vertices[ face.a ].add( cb ); - vertices[ face.b ].add( cb ); - vertices[ face.c ].add( cb ); + return this.array[ index * this.itemSize + 1 ]; - } + }, - } else { + setY: function ( index, y ) { - this.computeFaceNormals(); + this.array[ index * this.itemSize + 1 ] = y; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + return this; - face = this.faces[ f ]; + }, - vertices[ face.a ].add( face.normal ); - vertices[ face.b ].add( face.normal ); - vertices[ face.c ].add( face.normal ); + getZ: function ( index ) { - } + return this.array[ index * this.itemSize + 2 ]; - } + }, - for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { + setZ: function ( index, z ) { - vertices[ v ].normalize(); + this.array[ index * this.itemSize + 2 ] = z; - } + return this; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + }, - face = this.faces[ f ]; + getW: function ( index ) { - var vertexNormals = face.vertexNormals; + return this.array[ index * this.itemSize + 3 ]; - if ( vertexNormals.length === 3 ) { + }, - vertexNormals[ 0 ].copy( vertices[ face.a ] ); - vertexNormals[ 1 ].copy( vertices[ face.b ] ); - vertexNormals[ 2 ].copy( vertices[ face.c ] ); + setW: function ( index, w ) { - } else { + this.array[ index * this.itemSize + 3 ] = w; - vertexNormals[ 0 ] = vertices[ face.a ].clone(); - vertexNormals[ 1 ] = vertices[ face.b ].clone(); - vertexNormals[ 2 ] = vertices[ face.c ].clone(); + return this; - } + }, - } + setXY: function ( index, x, y ) { - if ( this.faces.length > 0 ) { + index *= this.itemSize; - this.normalsNeedUpdate = true; + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; - } + return this; }, - computeFlatVertexNormals: function () { + setXYZ: function ( index, x, y, z ) { + + index *= this.itemSize; - var f, fl, face; + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; - this.computeFaceNormals(); + return this; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + }, - face = this.faces[ f ]; + setXYZW: function ( index, x, y, z, w ) { - var vertexNormals = face.vertexNormals; + index *= this.itemSize; - if ( vertexNormals.length === 3 ) { + this.array[ index + 0 ] = x; + this.array[ index + 1 ] = y; + this.array[ index + 2 ] = z; + this.array[ index + 3 ] = w; - vertexNormals[ 0 ].copy( face.normal ); - vertexNormals[ 1 ].copy( face.normal ); - vertexNormals[ 2 ].copy( face.normal ); + return this; - } else { + }, - vertexNormals[ 0 ] = face.normal.clone(); - vertexNormals[ 1 ] = face.normal.clone(); - vertexNormals[ 2 ] = face.normal.clone(); + onUpload: function ( callback ) { - } + this.onUploadCallback = callback; - } + return this; - if ( this.faces.length > 0 ) { + }, - this.normalsNeedUpdate = true; + clone: function () { - } + return new this.constructor( this.array, this.itemSize ).copy( this ); }, - computeMorphNormals: function () { + toJSON: function () { - var i, il, f, fl, face; + return { + itemSize: this.itemSize, + type: this.array.constructor.name, + array: Array.prototype.slice.call( this.array ), + normalized: this.normalized + }; - // save original normals - // - create temp variables on first access - // otherwise just copy (for faster repeated calls) + } - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + } ); - face = this.faces[ f ]; + // - if ( ! face.__originalFaceNormal ) { + function Int8BufferAttribute( array, itemSize, normalized ) { - face.__originalFaceNormal = face.normal.clone(); + BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized ); - } else { + } - face.__originalFaceNormal.copy( face.normal ); + Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Int8BufferAttribute.prototype.constructor = Int8BufferAttribute; - } - if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; + function Uint8BufferAttribute( array, itemSize, normalized ) { - for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { + BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized ); - if ( ! face.__originalVertexNormals[ i ] ) { + } - face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); + Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute; - } else { - face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); + function Uint8ClampedBufferAttribute( array, itemSize, normalized ) { - } + BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized ); - } + } - } + Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute; - // use temp geometry to compute face and vertex normals for each morph - var tmpGeo = new Geometry(); - tmpGeo.faces = this.faces; + function Int16BufferAttribute( array, itemSize, normalized ) { - for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { + BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized ); - // create on first access + } - if ( ! this.morphNormals[ i ] ) { + Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Int16BufferAttribute.prototype.constructor = Int16BufferAttribute; - this.morphNormals[ i ] = {}; - this.morphNormals[ i ].faceNormals = []; - this.morphNormals[ i ].vertexNormals = []; - var dstNormalsFace = this.morphNormals[ i ].faceNormals; - var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; + function Uint16BufferAttribute( array, itemSize, normalized ) { - var faceNormal, vertexNormals; + BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized ); - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + } - faceNormal = new Vector3(); - vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() }; + Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute; - dstNormalsFace.push( faceNormal ); - dstNormalsVertex.push( vertexNormals ); - } + function Int32BufferAttribute( array, itemSize, normalized ) { - } + BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized ); - var morphNormals = this.morphNormals[ i ]; + } - // set vertices to morph target + Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Int32BufferAttribute.prototype.constructor = Int32BufferAttribute; - tmpGeo.vertices = this.morphTargets[ i ].vertices; - // compute morph normals + function Uint32BufferAttribute( array, itemSize, normalized ) { - tmpGeo.computeFaceNormals(); - tmpGeo.computeVertexNormals(); + BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized ); - // store morph normals + } - var faceNormal, vertexNormals; + Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute; - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { - face = this.faces[ f ]; + function Float32BufferAttribute( array, itemSize, normalized ) { - faceNormal = morphNormals.faceNormals[ f ]; - vertexNormals = morphNormals.vertexNormals[ f ]; + BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized ); - faceNormal.copy( face.normal ); + } - vertexNormals.a.copy( face.vertexNormals[ 0 ] ); - vertexNormals.b.copy( face.vertexNormals[ 1 ] ); - vertexNormals.c.copy( face.vertexNormals[ 2 ] ); + Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Float32BufferAttribute.prototype.constructor = Float32BufferAttribute; - } - } + function Float64BufferAttribute( array, itemSize, normalized ) { - // restore original normals + BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized ); - for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { + } - face = this.faces[ f ]; + Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); + Float64BufferAttribute.prototype.constructor = Float64BufferAttribute; - face.normal = face.__originalFaceNormal; - face.vertexNormals = face.__originalVertexNormals; + function DirectGeometry() { - } + this.vertices = []; + this.normals = []; + this.colors = []; + this.uvs = []; + this.uvs2 = []; - }, + this.groups = []; - computeBoundingBox: function () { + this.morphTargets = {}; - if ( this.boundingBox === null ) { + this.skinWeights = []; + this.skinIndices = []; - this.boundingBox = new Box3(); + // this.lineDistances = []; - } + this.boundingBox = null; + this.boundingSphere = null; - this.boundingBox.setFromPoints( this.vertices ); + // update flags - }, + this.verticesNeedUpdate = false; + this.normalsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.uvsNeedUpdate = false; + this.groupsNeedUpdate = false; - computeBoundingSphere: function () { + } - if ( this.boundingSphere === null ) { + Object.assign( DirectGeometry.prototype, { - this.boundingSphere = new Sphere(); + computeGroups: function ( geometry ) { - } + var groups = []; - this.boundingSphere.setFromPoints( this.vertices ); + var group, i; + var materialIndex = undefined; - }, + var faces = geometry.faces; - merge: function ( geometry, matrix, materialIndexOffset ) { + for ( i = 0; i < faces.length; i ++ ) { - if ( ! ( geometry && geometry.isGeometry ) ) { + var face = faces[ i ]; - console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); - return; + // materials - } + if ( face.materialIndex !== materialIndex ) { - var normalMatrix, - vertexOffset = this.vertices.length, - vertices1 = this.vertices, - vertices2 = geometry.vertices, - faces1 = this.faces, - faces2 = geometry.faces, - uvs1 = this.faceVertexUvs[ 0 ], - uvs2 = geometry.faceVertexUvs[ 0 ], - colors1 = this.colors, - colors2 = geometry.colors; + materialIndex = face.materialIndex; - if ( materialIndexOffset === undefined ) materialIndexOffset = 0; + if ( group !== undefined ) { - if ( matrix !== undefined ) { + group.count = ( i * 3 ) - group.start; + groups.push( group ); - normalMatrix = new Matrix3().getNormalMatrix( matrix ); + } - } + group = { + start: i * 3, + materialIndex: materialIndex + }; - // vertices + } - for ( var i = 0, il = vertices2.length; i < il; i ++ ) { + } - var vertex = vertices2[ i ]; + if ( group !== undefined ) { - var vertexCopy = vertex.clone(); + group.count = ( i * 3 ) - group.start; + groups.push( group ); - if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix ); + } - vertices1.push( vertexCopy ); + this.groups = groups; - } + }, - // colors + fromGeometry: function ( geometry ) { - for ( var i = 0, il = colors2.length; i < il; i ++ ) { + var faces = geometry.faces; + var vertices = geometry.vertices; + var faceVertexUvs = geometry.faceVertexUvs; - colors1.push( colors2[ i ].clone() ); + var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; + var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; - } + // morphs - // faces + var morphTargets = geometry.morphTargets; + var morphTargetsLength = morphTargets.length; - for ( i = 0, il = faces2.length; i < il; i ++ ) { + var morphTargetsPosition; - var face = faces2[ i ], faceCopy, normal, color, - faceVertexNormals = face.vertexNormals, - faceVertexColors = face.vertexColors; + if ( morphTargetsLength > 0 ) { - faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); - faceCopy.normal.copy( face.normal ); + morphTargetsPosition = []; - if ( normalMatrix !== undefined ) { + for ( var i = 0; i < morphTargetsLength; i ++ ) { - faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); + morphTargetsPosition[ i ] = { + name: morphTargets[ i ].name, + data: [] + }; } - for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { + this.morphTargets.position = morphTargetsPosition; - normal = faceVertexNormals[ j ].clone(); + } - if ( normalMatrix !== undefined ) { + var morphNormals = geometry.morphNormals; + var morphNormalsLength = morphNormals.length; - normal.applyMatrix3( normalMatrix ).normalize(); + var morphTargetsNormal; - } + if ( morphNormalsLength > 0 ) { - faceCopy.vertexNormals.push( normal ); + morphTargetsNormal = []; + + for ( var i$1 = 0; i$1 < morphNormalsLength; i$1 ++ ) { + + morphTargetsNormal[ i$1 ] = { + name: morphNormals[ i$1 ].name, + data: [] + }; } - faceCopy.color.copy( face.color ); + this.morphTargets.normal = morphTargetsNormal; - for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { + } - color = faceVertexColors[ j ]; - faceCopy.vertexColors.push( color.clone() ); + // skins - } + var skinIndices = geometry.skinIndices; + var skinWeights = geometry.skinWeights; - faceCopy.materialIndex = face.materialIndex + materialIndexOffset; + var hasSkinIndices = skinIndices.length === vertices.length; + var hasSkinWeights = skinWeights.length === vertices.length; - faces1.push( faceCopy ); + // + + if ( vertices.length > 0 && faces.length === 0 ) { + + console.error( 'THREE.DirectGeometry: Faceless geometries are not supported.' ); } - // uvs + for ( var i$2 = 0; i$2 < faces.length; i$2 ++ ) { - for ( i = 0, il = uvs2.length; i < il; i ++ ) { + var face = faces[ i$2 ]; - var uv = uvs2[ i ], uvCopy = []; + this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); - if ( uv === undefined ) { + var vertexNormals = face.vertexNormals; - continue; + if ( vertexNormals.length === 3 ) { - } + this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); + + } else { - for ( var j = 0, jl = uv.length; j < jl; j ++ ) { + var normal = face.normal; - uvCopy.push( uv[ j ].clone() ); + this.normals.push( normal, normal, normal ); } - uvs1.push( uvCopy ); + var vertexColors = face.vertexColors; - } + if ( vertexColors.length === 3 ) { - }, + this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); - mergeMesh: function ( mesh ) { + } else { - if ( ! ( mesh && mesh.isMesh ) ) { + var color = face.color; - console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); - return; + this.colors.push( color, color, color ); - } + } - if ( mesh.matrixAutoUpdate ) mesh.updateMatrix(); + if ( hasFaceVertexUv === true ) { - this.merge( mesh.geometry, mesh.matrix ); + var vertexUvs = faceVertexUvs[ 0 ][ i$2 ]; - }, + if ( vertexUvs !== undefined ) { - /* - * Checks for duplicate vertices with hashmap. - * Duplicated vertices are removed - * and faces' vertices are updated. - */ + this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); - mergeVertices: function () { + } else { - var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) - var unique = [], changes = []; + console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i$2 ); - var v, key; - var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001 - var precision = Math.pow( 10, precisionPoints ); - var i, il, face; - var indices, j, jl; + this.uvs.push( new Vector2(), new Vector2(), new Vector2() ); - for ( i = 0, il = this.vertices.length; i < il; i ++ ) { + } - v = this.vertices[ i ]; - key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); + } - if ( verticesMap[ key ] === undefined ) { + if ( hasFaceVertexUv2 === true ) { - verticesMap[ key ] = i; - unique.push( this.vertices[ i ] ); - changes[ i ] = unique.length - 1; + var vertexUvs$1 = faceVertexUvs[ 1 ][ i$2 ]; - } else { + if ( vertexUvs$1 !== undefined ) { - //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); - changes[ i ] = changes[ verticesMap[ key ] ]; + this.uvs2.push( vertexUvs$1[ 0 ], vertexUvs$1[ 1 ], vertexUvs$1[ 2 ] ); - } + } else { - } + console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i$2 ); + this.uvs2.push( new Vector2(), new Vector2(), new Vector2() ); - // if faces are completely degenerate after merging vertices, we - // have to remove them from the geometry. - var faceIndicesToRemove = []; + } + + } - for ( i = 0, il = this.faces.length; i < il; i ++ ) { + // morphs - face = this.faces[ i ]; + for ( var j = 0; j < morphTargetsLength; j ++ ) { - face.a = changes[ face.a ]; - face.b = changes[ face.b ]; - face.c = changes[ face.c ]; + var morphTarget = morphTargets[ j ].vertices; - indices = [ face.a, face.b, face.c ]; + morphTargetsPosition[ j ].data.push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); - // if any duplicate vertices are found in a Face3 - // we have to remove the face as nothing can be saved - for ( var n = 0; n < 3; n ++ ) { + } - if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { + for ( var j$1 = 0; j$1 < morphNormalsLength; j$1 ++ ) { - faceIndicesToRemove.push( i ); - break; + var morphNormal = morphNormals[ j$1 ].vertexNormals[ i$2 ]; - } + morphTargetsNormal[ j$1 ].data.push( morphNormal.a, morphNormal.b, morphNormal.c ); } - } + // skins - for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { + if ( hasSkinIndices ) { - var idx = faceIndicesToRemove[ i ]; + this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); - this.faces.splice( idx, 1 ); + } - for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { + if ( hasSkinWeights ) { - this.faceVertexUvs[ j ].splice( idx, 1 ); + this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); } } - // Use unique set of vertices + this.computeGroups( geometry ); - var diff = this.vertices.length - unique.length; - this.vertices = unique; - return diff; + this.verticesNeedUpdate = geometry.verticesNeedUpdate; + this.normalsNeedUpdate = geometry.normalsNeedUpdate; + this.colorsNeedUpdate = geometry.colorsNeedUpdate; + this.uvsNeedUpdate = geometry.uvsNeedUpdate; + this.groupsNeedUpdate = geometry.groupsNeedUpdate; - }, + if ( geometry.boundingSphere !== null ) { - setFromPoints: function ( points ) { + this.boundingSphere = geometry.boundingSphere.clone(); - this.vertices = []; + } - for ( var i = 0, l = points.length; i < l; i ++ ) { + if ( geometry.boundingBox !== null ) { - var point = points[ i ]; - this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); + this.boundingBox = geometry.boundingBox.clone(); } return this; - }, - - sortFacesByMaterialIndex: function () { - - var faces = this.faces; - var length = faces.length; + } - // tag faces + } ); - for ( var i = 0; i < length; i ++ ) { + function arrayMax( array ) { - faces[ i ]._id = i; + if ( array.length === 0 ) { return - Infinity; } - } + var max = array[ 0 ]; - // sort faces + for ( var i = 1, l = array.length; i < l; ++ i ) { - function materialIndexSort( a, b ) { + if ( array[ i ] > max ) { max = array[ i ]; } - return a.materialIndex - b.materialIndex; + } - } + return max; - faces.sort( materialIndexSort ); + } - // sort uvs + var _bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id - var uvs1 = this.faceVertexUvs[ 0 ]; - var uvs2 = this.faceVertexUvs[ 1 ]; + var _m1$2 = new Matrix4(); + var _obj = new Object3D(); + var _offset = new Vector3(); + var _box$2 = new Box3(); + var _boxMorphTargets = new Box3(); + var _vector$4 = new Vector3(); - var newUvs1, newUvs2; + function BufferGeometry() { - if ( uvs1 && uvs1.length === length ) newUvs1 = []; - if ( uvs2 && uvs2.length === length ) newUvs2 = []; + Object.defineProperty( this, 'id', { value: _bufferGeometryId += 2 } ); - for ( var i = 0; i < length; i ++ ) { + this.uuid = MathUtils.generateUUID(); - var id = faces[ i ]._id; + this.name = ''; + this.type = 'BufferGeometry'; - if ( newUvs1 ) newUvs1.push( uvs1[ id ] ); - if ( newUvs2 ) newUvs2.push( uvs2[ id ] ); + this.index = null; + this.attributes = {}; - } + this.morphAttributes = {}; + this.morphTargetsRelative = false; - if ( newUvs1 ) this.faceVertexUvs[ 0 ] = newUvs1; - if ( newUvs2 ) this.faceVertexUvs[ 1 ] = newUvs2; + this.groups = []; - }, + this.boundingBox = null; + this.boundingSphere = null; - toJSON: function () { + this.drawRange = { start: 0, count: Infinity }; - var data = { - metadata: { - version: 4.5, - type: 'Geometry', - generator: 'Geometry.toJSON' - } - }; + this.userData = {}; - // standard Geometry serialization + } - data.uuid = this.uuid; - data.type = this.type; - if ( this.name !== '' ) data.name = this.name; + BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - if ( this.parameters !== undefined ) { + constructor: BufferGeometry, - var parameters = this.parameters; + isBufferGeometry: true, - for ( var key in parameters ) { + getIndex: function () { - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; + return this.index; - } + }, - return data; + setIndex: function ( index ) { - } + if ( Array.isArray( index ) ) { - var vertices = []; + this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); - for ( var i = 0; i < this.vertices.length; i ++ ) { + } else { - var vertex = this.vertices[ i ]; - vertices.push( vertex.x, vertex.y, vertex.z ); + this.index = index; } - var faces = []; - var normals = []; - var normalsHash = {}; - var colors = []; - var colorsHash = {}; - var uvs = []; - var uvsHash = {}; + }, - for ( var i = 0; i < this.faces.length; i ++ ) { + getAttribute: function ( name ) { - var face = this.faces[ i ]; + return this.attributes[ name ]; - var hasMaterial = true; - var hasFaceUv = false; // deprecated - var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined; - var hasFaceNormal = face.normal.length() > 0; - var hasFaceVertexNormal = face.vertexNormals.length > 0; - var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1; - var hasFaceVertexColor = face.vertexColors.length > 0; + }, - var faceType = 0; + setAttribute: function ( name, attribute ) { - faceType = setBit( faceType, 0, 0 ); // isQuad - faceType = setBit( faceType, 1, hasMaterial ); - faceType = setBit( faceType, 2, hasFaceUv ); - faceType = setBit( faceType, 3, hasFaceVertexUv ); - faceType = setBit( faceType, 4, hasFaceNormal ); - faceType = setBit( faceType, 5, hasFaceVertexNormal ); - faceType = setBit( faceType, 6, hasFaceColor ); - faceType = setBit( faceType, 7, hasFaceVertexColor ); + this.attributes[ name ] = attribute; - faces.push( faceType ); - faces.push( face.a, face.b, face.c ); - faces.push( face.materialIndex ); + return this; - if ( hasFaceVertexUv ) { + }, - var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ]; + deleteAttribute: function ( name ) { - faces.push( - getUvIndex( faceVertexUvs[ 0 ] ), - getUvIndex( faceVertexUvs[ 1 ] ), - getUvIndex( faceVertexUvs[ 2 ] ) - ); + delete this.attributes[ name ]; - } + return this; - if ( hasFaceNormal ) { + }, - faces.push( getNormalIndex( face.normal ) ); + addGroup: function ( start, count, materialIndex ) { - } + this.groups.push( { - if ( hasFaceVertexNormal ) { + start: start, + count: count, + materialIndex: materialIndex !== undefined ? materialIndex : 0 - var vertexNormals = face.vertexNormals; + } ); - faces.push( - getNormalIndex( vertexNormals[ 0 ] ), - getNormalIndex( vertexNormals[ 1 ] ), - getNormalIndex( vertexNormals[ 2 ] ) - ); + }, - } + clearGroups: function () { - if ( hasFaceColor ) { + this.groups = []; - faces.push( getColorIndex( face.color ) ); + }, - } + setDrawRange: function ( start, count ) { - if ( hasFaceVertexColor ) { + this.drawRange.start = start; + this.drawRange.count = count; - var vertexColors = face.vertexColors; + }, - faces.push( - getColorIndex( vertexColors[ 0 ] ), - getColorIndex( vertexColors[ 1 ] ), - getColorIndex( vertexColors[ 2 ] ) - ); + applyMatrix4: function ( matrix ) { - } + var position = this.attributes.position; - } + if ( position !== undefined ) { - function setBit( value, position, enabled ) { + position.applyMatrix4( matrix ); - return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); + position.needsUpdate = true; } - function getNormalIndex( normal ) { - - var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); - - if ( normalsHash[ hash ] !== undefined ) { + var normal = this.attributes.normal; - return normalsHash[ hash ]; + if ( normal !== undefined ) { - } + var normalMatrix = new Matrix3().getNormalMatrix( matrix ); - normalsHash[ hash ] = normals.length / 3; - normals.push( normal.x, normal.y, normal.z ); + normal.applyNormalMatrix( normalMatrix ); - return normalsHash[ hash ]; + normal.needsUpdate = true; } - function getColorIndex( color ) { + var tangent = this.attributes.tangent; - var hash = color.r.toString() + color.g.toString() + color.b.toString(); + if ( tangent !== undefined ) { - if ( colorsHash[ hash ] !== undefined ) { + tangent.transformDirection( matrix ); - return colorsHash[ hash ]; + tangent.needsUpdate = true; - } + } - colorsHash[ hash ] = colors.length; - colors.push( color.getHex() ); + if ( this.boundingBox !== null ) { - return colorsHash[ hash ]; + this.computeBoundingBox(); } - function getUvIndex( uv ) { - - var hash = uv.x.toString() + uv.y.toString(); + if ( this.boundingSphere !== null ) { - if ( uvsHash[ hash ] !== undefined ) { + this.computeBoundingSphere(); - return uvsHash[ hash ]; + } - } + return this; - uvsHash[ hash ] = uvs.length / 2; - uvs.push( uv.x, uv.y ); + }, - return uvsHash[ hash ]; + rotateX: function ( angle ) { - } + // rotate geometry around world x-axis - data.data = {}; + _m1$2.makeRotationX( angle ); - data.data.vertices = vertices; - data.data.normals = normals; - if ( colors.length > 0 ) data.data.colors = colors; - if ( uvs.length > 0 ) data.data.uvs = [ uvs ]; // temporal backward compatibility - data.data.faces = faces; + this.applyMatrix4( _m1$2 ); - return data; + return this; }, - clone: function () { - - /* - // Handle primitives + rotateY: function ( angle ) { - var parameters = this.parameters; + // rotate geometry around world y-axis - if ( parameters !== undefined ) { + _m1$2.makeRotationY( angle ); - var values = []; + this.applyMatrix4( _m1$2 ); - for ( var key in parameters ) { + return this; - values.push( parameters[ key ] ); + }, - } + rotateZ: function ( angle ) { - var geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; + // rotate geometry around world z-axis - } + _m1$2.makeRotationZ( angle ); - return new this.constructor().copy( this ); - */ + this.applyMatrix4( _m1$2 ); - return new Geometry().copy( this ); + return this; }, - copy: function ( source ) { - - var i, il, j, jl, k, kl; + translate: function ( x, y, z ) { - // reset + // translate geometry - this.vertices = []; - this.colors = []; - this.faces = []; - this.faceVertexUvs = [[]]; - this.morphTargets = []; - this.morphNormals = []; - this.skinWeights = []; - this.skinIndices = []; - this.lineDistances = []; - this.boundingBox = null; - this.boundingSphere = null; + _m1$2.makeTranslation( x, y, z ); - // name + this.applyMatrix4( _m1$2 ); - this.name = source.name; + return this; - // vertices + }, - var vertices = source.vertices; + scale: function ( x, y, z ) { - for ( i = 0, il = vertices.length; i < il; i ++ ) { + // scale geometry - this.vertices.push( vertices[ i ].clone() ); + _m1$2.makeScale( x, y, z ); - } + this.applyMatrix4( _m1$2 ); - // colors + return this; - var colors = source.colors; + }, - for ( i = 0, il = colors.length; i < il; i ++ ) { + lookAt: function ( vector ) { - this.colors.push( colors[ i ].clone() ); + _obj.lookAt( vector ); - } + _obj.updateMatrix(); - // faces + this.applyMatrix4( _obj.matrix ); - var faces = source.faces; + return this; - for ( i = 0, il = faces.length; i < il; i ++ ) { + }, - this.faces.push( faces[ i ].clone() ); + center: function () { - } + this.computeBoundingBox(); - // face vertex uvs + this.boundingBox.getCenter( _offset ).negate(); - for ( i = 0, il = source.faceVertexUvs.length; i < il; i ++ ) { + this.translate( _offset.x, _offset.y, _offset.z ); - var faceVertexUvs = source.faceVertexUvs[ i ]; + return this; - if ( this.faceVertexUvs[ i ] === undefined ) { + }, - this.faceVertexUvs[ i ] = []; + setFromObject: function ( object ) { - } + // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); - for ( j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { + var geometry = object.geometry; - var uvs = faceVertexUvs[ j ], uvsCopy = []; + if ( object.isPoints || object.isLine ) { - for ( k = 0, kl = uvs.length; k < kl; k ++ ) { + var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 ); + var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 ); - var uv = uvs[ k ]; + this.setAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); + this.setAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); - uvsCopy.push( uv.clone() ); + if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { - } + var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 ); - this.faceVertexUvs[ i ].push( uvsCopy ); + this.setAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); } - } - - // morph targets - - var morphTargets = source.morphTargets; + if ( geometry.boundingSphere !== null ) { - for ( i = 0, il = morphTargets.length; i < il; i ++ ) { + this.boundingSphere = geometry.boundingSphere.clone(); - var morphTarget = {}; - morphTarget.name = morphTargets[ i ].name; + } - // vertices + if ( geometry.boundingBox !== null ) { - if ( morphTargets[ i ].vertices !== undefined ) { + this.boundingBox = geometry.boundingBox.clone(); - morphTarget.vertices = []; + } - for ( j = 0, jl = morphTargets[ i ].vertices.length; j < jl; j ++ ) { + } else if ( object.isMesh ) { - morphTarget.vertices.push( morphTargets[ i ].vertices[ j ].clone() ); + if ( geometry && geometry.isGeometry ) { - } + this.fromGeometry( geometry ); } - // normals - - if ( morphTargets[ i ].normals !== undefined ) { + } - morphTarget.normals = []; + return this; - for ( j = 0, jl = morphTargets[ i ].normals.length; j < jl; j ++ ) { + }, - morphTarget.normals.push( morphTargets[ i ].normals[ j ].clone() ); + setFromPoints: function ( points ) { - } + var position = []; - } + for ( var i = 0, l = points.length; i < l; i ++ ) { - this.morphTargets.push( morphTarget ); + var point = points[ i ]; + position.push( point.x, point.y, point.z || 0 ); } - // morph normals + this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); - var morphNormals = source.morphNormals; + return this; - for ( i = 0, il = morphNormals.length; i < il; i ++ ) { + }, - var morphNormal = {}; + updateFromObject: function ( object ) { - // vertex normals + var geometry = object.geometry; - if ( morphNormals[ i ].vertexNormals !== undefined ) { + if ( object.isMesh ) { - morphNormal.vertexNormals = []; + var direct = geometry.__directGeometry; - for ( j = 0, jl = morphNormals[ i ].vertexNormals.length; j < jl; j ++ ) { + if ( geometry.elementsNeedUpdate === true ) { - var srcVertexNormal = morphNormals[ i ].vertexNormals[ j ]; - var destVertexNormal = {}; + direct = undefined; + geometry.elementsNeedUpdate = false; - destVertexNormal.a = srcVertexNormal.a.clone(); - destVertexNormal.b = srcVertexNormal.b.clone(); - destVertexNormal.c = srcVertexNormal.c.clone(); + } - morphNormal.vertexNormals.push( destVertexNormal ); + if ( direct === undefined ) { - } + return this.fromGeometry( geometry ); } - // face normals + direct.verticesNeedUpdate = geometry.verticesNeedUpdate; + direct.normalsNeedUpdate = geometry.normalsNeedUpdate; + direct.colorsNeedUpdate = geometry.colorsNeedUpdate; + direct.uvsNeedUpdate = geometry.uvsNeedUpdate; + direct.groupsNeedUpdate = geometry.groupsNeedUpdate; + + geometry.verticesNeedUpdate = false; + geometry.normalsNeedUpdate = false; + geometry.colorsNeedUpdate = false; + geometry.uvsNeedUpdate = false; + geometry.groupsNeedUpdate = false; - if ( morphNormals[ i ].faceNormals !== undefined ) { + geometry = direct; - morphNormal.faceNormals = []; + } - for ( j = 0, jl = morphNormals[ i ].faceNormals.length; j < jl; j ++ ) { + if ( geometry.verticesNeedUpdate === true ) { - morphNormal.faceNormals.push( morphNormals[ i ].faceNormals[ j ].clone() ); + var attribute = this.attributes.position; - } + if ( attribute !== undefined ) { + + attribute.copyVector3sArray( geometry.vertices ); + attribute.needsUpdate = true; } - this.morphNormals.push( morphNormal ); + geometry.verticesNeedUpdate = false; } - // skin weights + if ( geometry.normalsNeedUpdate === true ) { - var skinWeights = source.skinWeights; + var attribute$1 = this.attributes.normal; + + if ( attribute$1 !== undefined ) { - for ( i = 0, il = skinWeights.length; i < il; i ++ ) { + attribute$1.copyVector3sArray( geometry.normals ); + attribute$1.needsUpdate = true; + + } - this.skinWeights.push( skinWeights[ i ].clone() ); + geometry.normalsNeedUpdate = false; } - // skin indices + if ( geometry.colorsNeedUpdate === true ) { - var skinIndices = source.skinIndices; + var attribute$2 = this.attributes.color; - for ( i = 0, il = skinIndices.length; i < il; i ++ ) { + if ( attribute$2 !== undefined ) { - this.skinIndices.push( skinIndices[ i ].clone() ); + attribute$2.copyColorsArray( geometry.colors ); + attribute$2.needsUpdate = true; + + } + + geometry.colorsNeedUpdate = false; } - // line distances + if ( geometry.uvsNeedUpdate ) { - var lineDistances = source.lineDistances; + var attribute$3 = this.attributes.uv; + + if ( attribute$3 !== undefined ) { - for ( i = 0, il = lineDistances.length; i < il; i ++ ) { + attribute$3.copyVector2sArray( geometry.uvs ); + attribute$3.needsUpdate = true; - this.lineDistances.push( lineDistances[ i ] ); + } + + geometry.uvsNeedUpdate = false; } - // bounding box + if ( geometry.lineDistancesNeedUpdate ) { - var boundingBox = source.boundingBox; + var attribute$4 = this.attributes.lineDistance; - if ( boundingBox !== null ) { + if ( attribute$4 !== undefined ) { - this.boundingBox = boundingBox.clone(); + attribute$4.copyArray( geometry.lineDistances ); + attribute$4.needsUpdate = true; - } + } - // bounding sphere + geometry.lineDistancesNeedUpdate = false; - var boundingSphere = source.boundingSphere; + } - if ( boundingSphere !== null ) { + if ( geometry.groupsNeedUpdate ) { - this.boundingSphere = boundingSphere.clone(); + geometry.computeGroups( object.geometry ); + this.groups = geometry.groups; + + geometry.groupsNeedUpdate = false; } - // update flags + return this; - this.elementsNeedUpdate = source.elementsNeedUpdate; - this.verticesNeedUpdate = source.verticesNeedUpdate; - this.uvsNeedUpdate = source.uvsNeedUpdate; - this.normalsNeedUpdate = source.normalsNeedUpdate; - this.colorsNeedUpdate = source.colorsNeedUpdate; - this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate; - this.groupsNeedUpdate = source.groupsNeedUpdate; + }, - return this; + fromGeometry: function ( geometry ) { + + geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry ); + + return this.fromDirectGeometry( geometry.__directGeometry ); }, - dispose: function () { + fromDirectGeometry: function ( geometry ) { - this.dispatchEvent( { type: 'dispose' } ); + var positions = new Float32Array( geometry.vertices.length * 3 ); + this.setAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); - } + if ( geometry.normals.length > 0 ) { - } ); + var normals = new Float32Array( geometry.normals.length * 3 ); + this.setAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function BufferAttribute( array, itemSize, normalized ) { + if ( geometry.colors.length > 0 ) { - if ( Array.isArray( array ) ) { + var colors = new Float32Array( geometry.colors.length * 3 ); + this.setAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + } - } + if ( geometry.uvs.length > 0 ) { - this.name = ''; + var uvs = new Float32Array( geometry.uvs.length * 2 ); + this.setAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); - this.array = array; - this.itemSize = itemSize; - this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized === true; + } - this.dynamic = false; - this.updateRange = { offset: 0, count: - 1 }; + if ( geometry.uvs2.length > 0 ) { - this.version = 0; + var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); + this.setAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); - } + } - Object.defineProperty( BufferAttribute.prototype, 'needsUpdate', { + // groups - set: function ( value ) { + this.groups = geometry.groups; - if ( value === true ) this.version ++; + // morphs - } + for ( var name in geometry.morphTargets ) { - } ); + var array = []; + var morphTargets = geometry.morphTargets[ name ]; - Object.assign( BufferAttribute.prototype, { + for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { - isBufferAttribute: true, + var morphTarget = morphTargets[ i ]; - onUploadCallback: function () {}, + var attribute = new Float32BufferAttribute( morphTarget.data.length * 3, 3 ); + attribute.name = morphTarget.name; - setArray: function ( array ) { + array.push( attribute.copyVector3sArray( morphTarget.data ) ); - if ( Array.isArray( array ) ) { + } - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + this.morphAttributes[ name ] = array; } - this.count = array !== undefined ? array.length / this.itemSize : 0; - this.array = array; + // skinning - return this; + if ( geometry.skinIndices.length > 0 ) { - }, + var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 ); + this.setAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); - setDynamic: function ( value ) { + } - this.dynamic = value; + if ( geometry.skinWeights.length > 0 ) { - return this; + var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 ); + this.setAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); - }, + } - copy: function ( 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; + if ( geometry.boundingSphere !== null ) { + + this.boundingSphere = geometry.boundingSphere.clone(); + + } + + if ( geometry.boundingBox !== null ) { + + this.boundingBox = geometry.boundingBox.clone(); - this.dynamic = source.dynamic; + } return this; }, - copyAt: function ( index1, attribute, index2 ) { - - index1 *= this.itemSize; - index2 *= attribute.itemSize; + computeBoundingBox: function () { - for ( var i = 0, l = this.itemSize; i < l; i ++ ) { + if ( this.boundingBox === null ) { - this.array[ index1 + i ] = attribute.array[ index2 + i ]; + this.boundingBox = new Box3(); } - return this; + var position = this.attributes.position; + var morphAttributesPosition = this.morphAttributes.position; - }, + if ( position !== undefined ) { - copyArray: function ( array ) { + this.boundingBox.setFromBufferAttribute( position ); - this.array.set( array ); + // process morph attributes if present - return this; + if ( morphAttributesPosition ) { - }, + for ( var i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - copyColorsArray: function ( colors ) { + var morphAttribute = morphAttributesPosition[ i ]; + _box$2.setFromBufferAttribute( morphAttribute ); - var array = this.array, offset = 0; + if ( this.morphTargetsRelative ) { - for ( var i = 0, l = colors.length; i < l; i ++ ) { + _vector$4.addVectors( this.boundingBox.min, _box$2.min ); + this.boundingBox.expandByPoint( _vector$4 ); - var color = colors[ i ]; + _vector$4.addVectors( this.boundingBox.max, _box$2.max ); + this.boundingBox.expandByPoint( _vector$4 ); - if ( color === undefined ) { + } else { - console.warn( 'THREE.BufferAttribute.copyColorsArray(): color is undefined', i ); - color = new Color(); + this.boundingBox.expandByPoint( _box$2.min ); + this.boundingBox.expandByPoint( _box$2.max ); + + } + + } } - array[ offset ++ ] = color.r; - array[ offset ++ ] = color.g; - array[ offset ++ ] = color.b; + } else { + + this.boundingBox.makeEmpty(); } - return this; + 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 ); - copyVector2sArray: function ( vectors ) { + } + + }, - var array = this.array, offset = 0; + computeBoundingSphere: function () { - for ( var i = 0, l = vectors.length; i < l; i ++ ) { + if ( this.boundingSphere === null ) { - var vector = vectors[ i ]; + this.boundingSphere = new Sphere(); - if ( vector === undefined ) { + } - console.warn( 'THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i ); - vector = new Vector2(); + var position = this.attributes.position; + var morphAttributesPosition = this.morphAttributes.position; - } + if ( position ) { - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; + // first, find the center of the bounding sphere - } + var center = this.boundingSphere.center; - return this; + _box$2.setFromBufferAttribute( position ); - }, + // process morph attributes if present - copyVector3sArray: function ( vectors ) { + if ( morphAttributesPosition ) { - var array = this.array, offset = 0; + for ( var i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { - for ( var i = 0, l = vectors.length; i < l; i ++ ) { + var morphAttribute = morphAttributesPosition[ i ]; + _boxMorphTargets.setFromBufferAttribute( morphAttribute ); - var vector = vectors[ i ]; + if ( this.morphTargetsRelative ) { - if ( vector === undefined ) { + _vector$4.addVectors( _box$2.min, _boxMorphTargets.min ); + _box$2.expandByPoint( _vector$4 ); - console.warn( 'THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i ); - vector = new Vector3(); + _vector$4.addVectors( _box$2.max, _boxMorphTargets.max ); + _box$2.expandByPoint( _vector$4 ); - } + } else { - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - array[ offset ++ ] = vector.z; + _box$2.expandByPoint( _boxMorphTargets.min ); + _box$2.expandByPoint( _boxMorphTargets.max ); - } + } - return this; + } - }, + } - copyVector4sArray: function ( vectors ) { + _box$2.getCenter( center ); - var array = this.array, offset = 0; + // second, try to find a boundingSphere with a radius smaller than the + // boundingSphere of the boundingBox: sqrt(3) smaller in the best case - for ( var i = 0, l = vectors.length; i < l; i ++ ) { + var maxRadiusSq = 0; - var vector = vectors[ i ]; + for ( var i$1 = 0, il$1 = position.count; i$1 < il$1; i$1 ++ ) { - if ( vector === undefined ) { + _vector$4.fromBufferAttribute( position, i$1 ); - console.warn( 'THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i ); - vector = new Vector4(); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) ); } - array[ offset ++ ] = vector.x; - array[ offset ++ ] = vector.y; - array[ offset ++ ] = vector.z; - array[ offset ++ ] = vector.w; + // process morph attributes if present - } + if ( morphAttributesPosition ) { - return this; + for ( var i$2 = 0, il$2 = morphAttributesPosition.length; i$2 < il$2; i$2 ++ ) { - }, + var morphAttribute$1 = morphAttributesPosition[ i$2 ]; + var morphTargetsRelative = this.morphTargetsRelative; - set: function ( value, offset ) { + for ( var j = 0, jl = morphAttribute$1.count; j < jl; j ++ ) { - if ( offset === undefined ) offset = 0; + _vector$4.fromBufferAttribute( morphAttribute$1, j ); - this.array.set( value, offset ); + if ( morphTargetsRelative ) { - return this; + _offset.fromBufferAttribute( position, j ); + _vector$4.add( _offset ); - }, + } - getX: function ( index ) { + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$4 ) ); - return this.array[ index * this.itemSize ]; + } - }, + } - setX: function ( index, x ) { + } - this.array[ index * this.itemSize ] = x; + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - return this; + if ( isNaN( this.boundingSphere.radius ) ) { + + console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); + + } + + } }, - getY: function ( index ) { + computeFaceNormals: function () { - return this.array[ index * this.itemSize + 1 ]; + // backwards compatibility }, - setY: function ( index, y ) { + computeVertexNormals: function () { - this.array[ index * this.itemSize + 1 ] = y; + var index = this.index; + var positionAttribute = this.getAttribute( 'position' ); - return this; + if ( positionAttribute !== undefined ) { - }, + var normalAttribute = this.getAttribute( 'normal' ); - getZ: function ( index ) { + if ( normalAttribute === undefined ) { - return this.array[ index * this.itemSize + 2 ]; + normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); + this.setAttribute( 'normal', normalAttribute ); - }, + } else { - setZ: function ( index, z ) { + // reset existing normals to zero - this.array[ index * this.itemSize + 2 ] = z; + for ( var i = 0, il = normalAttribute.count; i < il; i ++ ) { - return this; + normalAttribute.setXYZ( i, 0, 0, 0 ); - }, + } - getW: function ( index ) { + } - return this.array[ index * this.itemSize + 3 ]; + var pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); + var nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); + var cb = new Vector3(), ab = new Vector3(); - }, + // indexed elements - setW: function ( index, w ) { + if ( index ) { - this.array[ index * this.itemSize + 3 ] = w; + for ( var i$1 = 0, il$1 = index.count; i$1 < il$1; i$1 += 3 ) { - return this; + var vA = index.getX( i$1 + 0 ); + var vB = index.getX( i$1 + 1 ); + var vC = index.getX( i$1 + 2 ); - }, + pA.fromBufferAttribute( positionAttribute, vA ); + pB.fromBufferAttribute( positionAttribute, vB ); + pC.fromBufferAttribute( positionAttribute, vC ); - setXY: function ( index, x, y ) { + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - index *= this.itemSize; + nA.fromBufferAttribute( normalAttribute, vA ); + nB.fromBufferAttribute( normalAttribute, vB ); + nC.fromBufferAttribute( normalAttribute, vC ); - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; + nA.add( cb ); + nB.add( cb ); + nC.add( cb ); - return this; + 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 ); - }, + } - setXYZ: function ( index, x, y, z ) { + } else { - index *= this.itemSize; + // non-indexed elements (unconnected triangle soup) - this.array[ index + 0 ] = x; - this.array[ index + 1 ] = y; - this.array[ index + 2 ] = z; + for ( var i$2 = 0, il$2 = positionAttribute.count; i$2 < il$2; i$2 += 3 ) { - return this; + pA.fromBufferAttribute( positionAttribute, i$2 + 0 ); + pB.fromBufferAttribute( positionAttribute, i$2 + 1 ); + pC.fromBufferAttribute( positionAttribute, i$2 + 2 ); - }, + cb.subVectors( pC, pB ); + ab.subVectors( pA, pB ); + cb.cross( ab ); - setXYZW: function ( index, x, y, z, w ) { + normalAttribute.setXYZ( i$2 + 0, cb.x, cb.y, cb.z ); + normalAttribute.setXYZ( i$2 + 1, cb.x, cb.y, cb.z ); + normalAttribute.setXYZ( i$2 + 2, cb.x, cb.y, cb.z ); - 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; + this.normalizeNormals(); + + normalAttribute.needsUpdate = true; + + } }, - onUpload: function ( callback ) { + merge: function ( geometry, offset ) { - this.onUploadCallback = callback; + if ( ! ( geometry && geometry.isBufferGeometry ) ) { - return this; + console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); + return; - }, + } - clone: function () { + if ( offset === undefined ) { - return new this.constructor( this.array, this.itemSize ).copy( this ); + offset = 0; - } + console.warn( + 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. ' + + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.' + ); - } ); + } - // + var attributes = this.attributes; - function Int8BufferAttribute( array, itemSize, normalized ) { + for ( var key in attributes ) { - BufferAttribute.call( this, new Int8Array( array ), itemSize, normalized ); + if ( geometry.attributes[ key ] === undefined ) { continue; } - } + var attribute1 = attributes[ key ]; + var attributeArray1 = attribute1.array; - Int8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Int8BufferAttribute.prototype.constructor = Int8BufferAttribute; + var attribute2 = geometry.attributes[ key ]; + var attributeArray2 = attribute2.array; + var attributeOffset = attribute2.itemSize * offset; + var length = Math.min( attributeArray2.length, attributeArray1.length - attributeOffset ); - function Uint8BufferAttribute( array, itemSize, normalized ) { + for ( var i = 0, j = attributeOffset; i < length; i ++, j ++ ) { - BufferAttribute.call( this, new Uint8Array( array ), itemSize, normalized ); + attributeArray1[ j ] = attributeArray2[ i ]; - } + } - Uint8BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute; + } + return this; - function Uint8ClampedBufferAttribute( array, itemSize, normalized ) { + }, - BufferAttribute.call( this, new Uint8ClampedArray( array ), itemSize, normalized ); + normalizeNormals: function () { - } + var normals = this.attributes.normal; - Uint8ClampedBufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute; + for ( var i = 0, il = normals.count; i < il; i ++ ) { + _vector$4.fromBufferAttribute( normals, i ); - function Int16BufferAttribute( array, itemSize, normalized ) { + _vector$4.normalize(); - BufferAttribute.call( this, new Int16Array( array ), itemSize, normalized ); + normals.setXYZ( i, _vector$4.x, _vector$4.y, _vector$4.z ); - } + } - Int16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Int16BufferAttribute.prototype.constructor = Int16BufferAttribute; + }, + toNonIndexed: function () { - function Uint16BufferAttribute( array, itemSize, normalized ) { + function convertBufferAttribute( attribute, indices ) { - BufferAttribute.call( this, new Uint16Array( array ), itemSize, normalized ); + var array = attribute.array; + var itemSize = attribute.itemSize; + var normalized = attribute.normalized; - } + var array2 = new array.constructor( indices.length * itemSize ); - Uint16BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute; + var index = 0, index2 = 0; + for ( var i = 0, l = indices.length; i < l; i ++ ) { - function Int32BufferAttribute( array, itemSize, normalized ) { + index = indices[ i ] * itemSize; - BufferAttribute.call( this, new Int32Array( array ), itemSize, normalized ); + for ( var j = 0; j < itemSize; j ++ ) { - } + array2[ index2 ++ ] = array[ index ++ ]; - Int32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Int32BufferAttribute.prototype.constructor = Int32BufferAttribute; + } + } - function Uint32BufferAttribute( array, itemSize, normalized ) { + return new BufferAttribute( array2, itemSize, normalized ); - BufferAttribute.call( this, new Uint32Array( array ), itemSize, normalized ); + } - } + // - Uint32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute; + if ( this.index === null ) { + console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' ); + return this; - function Float32BufferAttribute( array, itemSize, normalized ) { + } - BufferAttribute.call( this, new Float32Array( array ), itemSize, normalized ); + var geometry2 = new BufferGeometry(); - } + var indices = this.index.array; + var attributes = this.attributes; - Float32BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Float32BufferAttribute.prototype.constructor = Float32BufferAttribute; + // attributes + for ( var name in attributes ) { - function Float64BufferAttribute( array, itemSize, normalized ) { + var attribute = attributes[ name ]; - BufferAttribute.call( this, new Float64Array( array ), itemSize, normalized ); + var newAttribute = convertBufferAttribute( attribute, indices ); - } + geometry2.setAttribute( name, newAttribute ); - Float64BufferAttribute.prototype = Object.create( BufferAttribute.prototype ); - Float64BufferAttribute.prototype.constructor = Float64BufferAttribute; + } - /** - * @author mrdoob / http://mrdoob.com/ - */ + // morph attributes - function DirectGeometry() { + var morphAttributes = this.morphAttributes; - this.vertices = []; - this.normals = []; - this.colors = []; - this.uvs = []; - this.uvs2 = []; + for ( var name$1 in morphAttributes ) { - this.groups = []; + var morphArray = []; + var morphAttribute = morphAttributes[ name$1 ]; // morphAttribute: array of Float32BufferAttributes - this.morphTargets = {}; + for ( var i = 0, il = morphAttribute.length; i < il; i ++ ) { - this.skinWeights = []; - this.skinIndices = []; + var attribute$1 = morphAttribute[ i ]; - // this.lineDistances = []; + var newAttribute$1 = convertBufferAttribute( attribute$1, indices ); - this.boundingBox = null; - this.boundingSphere = null; + morphArray.push( newAttribute$1 ); - // update flags + } - this.verticesNeedUpdate = false; - this.normalsNeedUpdate = false; - this.colorsNeedUpdate = false; - this.uvsNeedUpdate = false; - this.groupsNeedUpdate = false; + geometry2.morphAttributes[ name$1 ] = morphArray; - } + } - Object.assign( DirectGeometry.prototype, { + geometry2.morphTargetsRelative = this.morphTargetsRelative; - computeGroups: function ( geometry ) { + // groups - var group; - var groups = []; - var materialIndex = undefined; + var groups = this.groups; - var faces = geometry.faces; + for ( var i$1 = 0, l = groups.length; i$1 < l; i$1 ++ ) { - for ( var i = 0; i < faces.length; i ++ ) { + var group = groups[ i$1 ]; + geometry2.addGroup( group.start, group.count, group.materialIndex ); - var face = faces[ i ]; + } - // materials + return geometry2; - if ( face.materialIndex !== materialIndex ) { + }, - materialIndex = face.materialIndex; + toJSON: function () { - if ( group !== undefined ) { + var data = { + metadata: { + version: 4.5, + type: 'BufferGeometry', + generator: 'BufferGeometry.toJSON' + } + }; - group.count = ( i * 3 ) - group.start; - groups.push( group ); + // 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; } - group = { - start: i * 3, - materialIndex: materialIndex - }; + if ( this.parameters !== undefined ) { - } + var parameters = this.parameters; - } + for ( var key in parameters ) { - if ( group !== undefined ) { + if ( parameters[ key ] !== undefined ) { data[ key ] = parameters[ key ]; } - group.count = ( i * 3 ) - group.start; - groups.push( group ); + } + + return data; } - this.groups = groups; + data.data = { attributes: {} }; - }, + var index = this.index; - fromGeometry: function ( geometry ) { + if ( index !== null ) { - var faces = geometry.faces; - var vertices = geometry.vertices; - var faceVertexUvs = geometry.faceVertexUvs; + data.data.index = { + type: index.array.constructor.name, + array: Array.prototype.slice.call( index.array ) + }; - var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0; - var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0; + } - // morphs + var attributes = this.attributes; - var morphTargets = geometry.morphTargets; - var morphTargetsLength = morphTargets.length; + for ( var key$1 in attributes ) { - var morphTargetsPosition; + var attribute = attributes[ key$1 ]; - if ( morphTargetsLength > 0 ) { + var attributeData = attribute.toJSON( data.data ); - morphTargetsPosition = []; + if ( attribute.name !== '' ) { attributeData.name = attribute.name; } - for ( var i = 0; i < morphTargetsLength; i ++ ) { + data.data.attributes[ key$1 ] = attributeData; - morphTargetsPosition[ i ] = { - name: morphTargets[ i ].name, - data: [] - }; + } - } + var morphAttributes = {}; + var hasMorphAttributes = false; - this.morphTargets.position = morphTargetsPosition; + for ( var key$2 in this.morphAttributes ) { - } + var attributeArray = this.morphAttributes[ key$2 ]; - var morphNormals = geometry.morphNormals; - var morphNormalsLength = morphNormals.length; + var array = []; - var morphTargetsNormal; + for ( var i = 0, il = attributeArray.length; i < il; i ++ ) { - if ( morphNormalsLength > 0 ) { + var attribute$1 = attributeArray[ i ]; - morphTargetsNormal = []; + var attributeData$1 = attribute$1.toJSON( data.data ); - for ( var i = 0; i < morphNormalsLength; i ++ ) { + if ( attribute$1.name !== '' ) { attributeData$1.name = attribute$1.name; } - morphTargetsNormal[ i ] = { - name: morphNormals[ i ].name, - data: [] - }; + array.push( attributeData$1 ); } - this.morphTargets.normal = morphTargetsNormal; - - } + if ( array.length > 0 ) { - // skins + morphAttributes[ key$2 ] = array; - var skinIndices = geometry.skinIndices; - var skinWeights = geometry.skinWeights; + hasMorphAttributes = true; - var hasSkinIndices = skinIndices.length === vertices.length; - var hasSkinWeights = skinWeights.length === vertices.length; + } - // + } - if ( vertices.length > 0 && faces.length === 0 ) { + if ( hasMorphAttributes ) { - console.error( 'THREE.DirectGeometry: Faceless geometries are not supported.' ); + data.data.morphAttributes = morphAttributes; + data.data.morphTargetsRelative = this.morphTargetsRelative; } - for ( var i = 0; i < faces.length; i ++ ) { - - var face = faces[ i ]; + var groups = this.groups; - this.vertices.push( vertices[ face.a ], vertices[ face.b ], vertices[ face.c ] ); + if ( groups.length > 0 ) { - var vertexNormals = face.vertexNormals; + data.data.groups = JSON.parse( JSON.stringify( groups ) ); - if ( vertexNormals.length === 3 ) { + } - this.normals.push( vertexNormals[ 0 ], vertexNormals[ 1 ], vertexNormals[ 2 ] ); + var boundingSphere = this.boundingSphere; - } else { + if ( boundingSphere !== null ) { - var normal = face.normal; + data.data.boundingSphere = { + center: boundingSphere.center.toArray(), + radius: boundingSphere.radius + }; - this.normals.push( normal, normal, normal ); + } - } + return data; - var vertexColors = face.vertexColors; + }, - if ( vertexColors.length === 3 ) { + clone: function () { - this.colors.push( vertexColors[ 0 ], vertexColors[ 1 ], vertexColors[ 2 ] ); + /* + // Handle primitives - } else { + const parameters = this.parameters; - var color = face.color; + if ( parameters !== undefined ) { - this.colors.push( color, color, color ); + const values = []; - } + for ( const key in parameters ) { - if ( hasFaceVertexUv === true ) { + values.push( parameters[ key ] ); - var vertexUvs = faceVertexUvs[ 0 ][ i ]; + } - if ( vertexUvs !== undefined ) { + const geometry = Object.create( this.constructor.prototype ); + this.constructor.apply( geometry, values ); + return geometry; - this.uvs.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); + } - } else { + return new this.constructor().copy( this ); + */ - console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i ); + return new BufferGeometry().copy( this ); - this.uvs.push( new Vector2(), new Vector2(), new Vector2() ); + }, - } + copy: function ( source ) { - } + // reset - if ( hasFaceVertexUv2 === true ) { + this.index = null; + this.attributes = {}; + this.morphAttributes = {}; + this.groups = []; + this.boundingBox = null; + this.boundingSphere = null; - var vertexUvs = faceVertexUvs[ 1 ][ i ]; + // used for storing cloned, shared data - if ( vertexUvs !== undefined ) { + var data = {}; - this.uvs2.push( vertexUvs[ 0 ], vertexUvs[ 1 ], vertexUvs[ 2 ] ); + // name - } else { + this.name = source.name; - console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i ); + // index - this.uvs2.push( new Vector2(), new Vector2(), new Vector2() ); + var index = source.index; - } + if ( index !== null ) { - } + this.setIndex( index.clone( data ) ); - // morphs + } - for ( var j = 0; j < morphTargetsLength; j ++ ) { + // attributes - var morphTarget = morphTargets[ j ].vertices; + var attributes = source.attributes; - morphTargetsPosition[ j ].data.push( morphTarget[ face.a ], morphTarget[ face.b ], morphTarget[ face.c ] ); + for ( var name in attributes ) { - } + var attribute = attributes[ name ]; + this.setAttribute( name, attribute.clone( data ) ); - for ( var j = 0; j < morphNormalsLength; j ++ ) { + } - var morphNormal = morphNormals[ j ].vertexNormals[ i ]; + // morph attributes - morphTargetsNormal[ j ].data.push( morphNormal.a, morphNormal.b, morphNormal.c ); + var morphAttributes = source.morphAttributes; - } + for ( var name$1 in morphAttributes ) { - // skins + var array = []; + var morphAttribute = morphAttributes[ name$1 ]; // morphAttribute: array of Float32BufferAttributes - if ( hasSkinIndices ) { + for ( var i = 0, l = morphAttribute.length; i < l; i ++ ) { - this.skinIndices.push( skinIndices[ face.a ], skinIndices[ face.b ], skinIndices[ face.c ] ); + array.push( morphAttribute[ i ].clone( data ) ); } - if ( hasSkinWeights ) { - - this.skinWeights.push( skinWeights[ face.a ], skinWeights[ face.b ], skinWeights[ face.c ] ); - - } + this.morphAttributes[ name$1 ] = array; } - this.computeGroups( geometry ); + this.morphTargetsRelative = source.morphTargetsRelative; - this.verticesNeedUpdate = geometry.verticesNeedUpdate; - this.normalsNeedUpdate = geometry.normalsNeedUpdate; - this.colorsNeedUpdate = geometry.colorsNeedUpdate; - this.uvsNeedUpdate = geometry.uvsNeedUpdate; - this.groupsNeedUpdate = geometry.groupsNeedUpdate; + // groups - return this; + var groups = source.groups; - } + for ( var i$1 = 0, l$1 = groups.length; i$1 < l$1; i$1 ++ ) { - } ); + var group = groups[ i$1 ]; + this.addGroup( group.start, group.count, group.materialIndex ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function arrayMax( array ) { + // bounding box - if ( array.length === 0 ) return - Infinity; + var boundingBox = source.boundingBox; - var max = array[ 0 ]; + if ( boundingBox !== null ) { - for ( var i = 1, l = array.length; i < l; ++ i ) { + this.boundingBox = boundingBox.clone(); - if ( array[ i ] > max ) max = array[ i ]; + } - } + // bounding sphere - return max; + var boundingSphere = source.boundingSphere; - } + if ( boundingSphere !== null ) { - /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + this.boundingSphere = boundingSphere.clone(); - var bufferGeometryId = 1; // BufferGeometry uses odd numbers as Id + } - function BufferGeometry() { + // draw range - Object.defineProperty( this, 'id', { value: bufferGeometryId += 2 } ); + this.drawRange.start = source.drawRange.start; + this.drawRange.count = source.drawRange.count; - this.uuid = _Math.generateUUID(); + // user data - this.name = ''; - this.type = 'BufferGeometry'; + this.userData = source.userData; - this.index = null; - this.attributes = {}; + return this; - this.morphAttributes = {}; + }, - this.groups = []; + dispose: function () { - this.boundingBox = null; - this.boundingSphere = null; + this.dispatchEvent( { type: 'dispose' } ); - this.drawRange = { start: 0, count: Infinity }; + } - this.userData = {}; + } ); - } + var _inverseMatrix = new Matrix4(); + var _ray = new Ray(); + var _sphere = new Sphere(); - BufferGeometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + var _vA = new Vector3(); + var _vB = new Vector3(); + var _vC = new Vector3(); - constructor: BufferGeometry, + var _tempA = new Vector3(); + var _tempB = new Vector3(); + var _tempC = new Vector3(); - isBufferGeometry: true, + var _morphA = new Vector3(); + var _morphB = new Vector3(); + var _morphC = new Vector3(); - getIndex: function () { + var _uvA = new Vector2(); + var _uvB = new Vector2(); + var _uvC = new Vector2(); - return this.index; + var _intersectionPoint = new Vector3(); + var _intersectionPointWorld = new Vector3(); - }, + function Mesh( geometry, material ) { - setIndex: function ( index ) { + Object3D.call( this ); - if ( Array.isArray( index ) ) { + this.type = 'Mesh'; - this.index = new ( arrayMax( index ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new MeshBasicMaterial(); - } else { + this.updateMorphTargets(); - this.index = index; + } - } + Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), { - }, + constructor: Mesh, - addAttribute: function ( name, attribute ) { + isMesh: true, - if ( ! ( attribute && attribute.isBufferAttribute ) && ! ( attribute && attribute.isInterleavedBufferAttribute ) ) { + copy: function ( source ) { - console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' ); + Object3D.prototype.copy.call( this, source ); + + if ( source.morphTargetInfluences !== undefined ) { - return this.addAttribute( name, new BufferAttribute( arguments[ 1 ], arguments[ 2 ] ) ); + this.morphTargetInfluences = source.morphTargetInfluences.slice(); } - if ( name === 'index' ) { - - console.warn( 'THREE.BufferGeometry.addAttribute: Use .setIndex() for index attribute.' ); - this.setIndex( attribute ); + if ( source.morphTargetDictionary !== undefined ) { - return this; + this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); } - this.attributes[ name ] = attribute; + this.material = source.material; + this.geometry = source.geometry; return this; }, - getAttribute: function ( name ) { - - return this.attributes[ name ]; - - }, - - removeAttribute: function ( name ) { + updateMorphTargets: function () { - delete this.attributes[ name ]; + var geometry = this.geometry; - return this; + if ( geometry.isBufferGeometry ) { - }, + var morphAttributes = geometry.morphAttributes; + var keys = Object.keys( morphAttributes ); - addGroup: function ( start, count, materialIndex ) { + if ( keys.length > 0 ) { - this.groups.push( { + var morphAttribute = morphAttributes[ keys[ 0 ] ]; - start: start, - count: count, - materialIndex: materialIndex !== undefined ? materialIndex : 0 + if ( morphAttribute !== undefined ) { - } ); + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - }, + for ( var m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - clearGroups: function () { + var name = morphAttribute[ m ].name || String( m ); - this.groups = []; + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; - }, + } - setDrawRange: function ( start, count ) { + } - this.drawRange.start = start; - this.drawRange.count = count; + } - }, + } else { - applyMatrix: function ( matrix ) { + var morphTargets = geometry.morphTargets; - var position = this.attributes.position; + if ( morphTargets !== undefined && morphTargets.length > 0 ) { - if ( position !== undefined ) { + console.error( 'THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - matrix.applyToBufferAttribute( position ); - position.needsUpdate = true; + } } - var normal = this.attributes.normal; - - if ( normal !== undefined ) { - - var normalMatrix = new Matrix3().getNormalMatrix( matrix ); + }, - normalMatrix.applyToBufferAttribute( normal ); - normal.needsUpdate = true; + raycast: function ( raycaster, intersects ) { - } + var geometry = this.geometry; + var material = this.material; + var matrixWorld = this.matrixWorld; - if ( this.boundingBox !== null ) { + if ( material === undefined ) { return; } - this.computeBoundingBox(); + // Checking boundingSphere distance to ray - } + if ( geometry.boundingSphere === null ) { geometry.computeBoundingSphere(); } - if ( this.boundingSphere !== null ) { + _sphere.copy( geometry.boundingSphere ); + _sphere.applyMatrix4( matrixWorld ); - this.computeBoundingSphere(); + if ( raycaster.ray.intersectsSphere( _sphere ) === false ) { return; } - } + // - return this; + _inverseMatrix.getInverse( matrixWorld ); + _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); - }, + // Check boundingBox before continuing - rotateX: function () { + if ( geometry.boundingBox !== null ) { - // rotate geometry around world x-axis + if ( _ray.intersectsBox( geometry.boundingBox ) === false ) { return; } - var m1 = new Matrix4(); + } - return function rotateX( angle ) { + var intersection; - m1.makeRotationX( angle ); + if ( geometry.isBufferGeometry ) { - this.applyMatrix( m1 ); + var index = geometry.index; + var position = geometry.attributes.position; + var morphPosition = geometry.morphAttributes.position; + var morphTargetsRelative = geometry.morphTargetsRelative; + var uv = geometry.attributes.uv; + var uv2 = geometry.attributes.uv2; + var groups = geometry.groups; + var drawRange = geometry.drawRange; - return this; + if ( index !== null ) { - }; + // indexed buffer geometry - }(), + if ( Array.isArray( material ) ) { - rotateY: function () { + for ( var i = 0, il = groups.length; i < il; i ++ ) { - // rotate geometry around world y-axis + var group = groups[ i ]; + var groupMaterial = material[ group.materialIndex ]; - var m1 = new Matrix4(); + var start = Math.max( group.start, drawRange.start ); + var end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); - return function rotateY( angle ) { + for ( var j = start, jl = end; j < jl; j += 3 ) { - m1.makeRotationY( angle ); + var a = index.getX( j ); + var b = index.getX( j + 1 ); + var c = index.getX( j + 2 ); - this.applyMatrix( m1 ); + intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); - return this; + if ( intersection ) { - }; + intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics + intersection.face.materialIndex = group.materialIndex; + intersects.push( intersection ); - }(), + } - rotateZ: function () { + } - // rotate geometry around world z-axis + } - var m1 = new Matrix4(); + } else { - return function rotateZ( angle ) { + var start$1 = Math.max( 0, drawRange.start ); + var end$1 = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - m1.makeRotationZ( angle ); + for ( var i$1 = start$1, il$1 = end$1; i$1 < il$1; i$1 += 3 ) { - this.applyMatrix( m1 ); + var a$1 = index.getX( i$1 ); + var b$1 = index.getX( i$1 + 1 ); + var c$1 = index.getX( i$1 + 2 ); - return this; + intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a$1, b$1, c$1 ); - }; + if ( intersection ) { - }(), + intersection.faceIndex = Math.floor( i$1 / 3 ); // triangle number in indexed buffer semantics + intersects.push( intersection ); - translate: function () { + } - // translate geometry + } - var m1 = new Matrix4(); + } - return function translate( x, y, z ) { + } else if ( position !== undefined ) { - m1.makeTranslation( x, y, z ); + // non-indexed buffer geometry - this.applyMatrix( m1 ); + if ( Array.isArray( material ) ) { - return this; + for ( var i$2 = 0, il$2 = groups.length; i$2 < il$2; i$2 ++ ) { - }; + var group$1 = groups[ i$2 ]; + var groupMaterial$1 = material[ group$1.materialIndex ]; - }(), + var start$2 = Math.max( group$1.start, drawRange.start ); + var end$2 = Math.min( ( group$1.start + group$1.count ), ( drawRange.start + drawRange.count ) ); - scale: function () { + for ( var j$1 = start$2, jl$1 = end$2; j$1 < jl$1; j$1 += 3 ) { - // scale geometry + var a$2 = j$1; + var b$2 = j$1 + 1; + var c$2 = j$1 + 2; - var m1 = new Matrix4(); + intersection = checkBufferGeometryIntersection( this, groupMaterial$1, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a$2, b$2, c$2 ); - return function scale( x, y, z ) { + if ( intersection ) { - m1.makeScale( x, y, z ); + intersection.faceIndex = Math.floor( j$1 / 3 ); // triangle number in non-indexed buffer semantics + intersection.face.materialIndex = group$1.materialIndex; + intersects.push( intersection ); - this.applyMatrix( m1 ); + } - return this; + } - }; + } - }(), + } else { - lookAt: function () { + var start$3 = Math.max( 0, drawRange.start ); + var end$3 = Math.min( position.count, ( drawRange.start + drawRange.count ) ); - var obj = new Object3D(); + for ( var i$3 = start$3, il$3 = end$3; i$3 < il$3; i$3 += 3 ) { - return function lookAt( vector ) { + var a$3 = i$3; + var b$3 = i$3 + 1; + var c$3 = i$3 + 2; - obj.lookAt( vector ); + intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a$3, b$3, c$3 ); - obj.updateMatrix(); + if ( intersection ) { - this.applyMatrix( obj.matrix ); + intersection.faceIndex = Math.floor( i$3 / 3 ); // triangle number in non-indexed buffer semantics + intersects.push( intersection ); - }; + } - }(), + } - center: function () { + } - var offset = new Vector3(); + } - return function center() { + } else if ( geometry.isGeometry ) { - this.computeBoundingBox(); + var isMultiMaterial = Array.isArray( material ); - this.boundingBox.getCenter( offset ).negate(); + var vertices = geometry.vertices; + var faces = geometry.faces; + var uvs; - this.translate( offset.x, offset.y, offset.z ); + var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; + if ( faceVertexUvs.length > 0 ) { uvs = faceVertexUvs; } - return this; + for ( var f = 0, fl = faces.length; f < fl; f ++ ) { - }; + var face = faces[ f ]; + var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material; - }(), + if ( faceMaterial === undefined ) { continue; } - setFromObject: function ( object ) { + var fvA = vertices[ face.a ]; + var fvB = vertices[ face.b ]; + var fvC = vertices[ face.c ]; - // console.log( 'THREE.BufferGeometry.setFromObject(). Converting', object, this ); + intersection = checkIntersection( this, faceMaterial, raycaster, _ray, fvA, fvB, fvC, _intersectionPoint ); - var geometry = object.geometry; + if ( intersection ) { - if ( object.isPoints || object.isLine ) { + if ( uvs && uvs[ f ] ) { - var positions = new Float32BufferAttribute( geometry.vertices.length * 3, 3 ); - var colors = new Float32BufferAttribute( geometry.colors.length * 3, 3 ); + var uvs_f = uvs[ f ]; + _uvA.copy( uvs_f[ 0 ] ); + _uvB.copy( uvs_f[ 1 ] ); + _uvC.copy( uvs_f[ 2 ] ); - this.addAttribute( 'position', positions.copyVector3sArray( geometry.vertices ) ); - this.addAttribute( 'color', colors.copyColorsArray( geometry.colors ) ); + intersection.uv = Triangle.getUV( _intersectionPoint, fvA, fvB, fvC, _uvA, _uvB, _uvC, new Vector2() ); - if ( geometry.lineDistances && geometry.lineDistances.length === geometry.vertices.length ) { + } - var lineDistances = new Float32BufferAttribute( geometry.lineDistances.length, 1 ); + intersection.face = face; + intersection.faceIndex = f; + intersects.push( intersection ); - this.addAttribute( 'lineDistance', lineDistances.copyArray( geometry.lineDistances ) ); + } } - if ( geometry.boundingSphere !== null ) { - - this.boundingSphere = geometry.boundingSphere.clone(); + } - } + } - if ( geometry.boundingBox !== null ) { + } ); - this.boundingBox = geometry.boundingBox.clone(); + function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { - } + var intersect; - } else if ( object.isMesh ) { + if ( material.side === BackSide ) { - if ( geometry && geometry.isGeometry ) { + intersect = ray.intersectTriangle( pC, pB, pA, true, point ); - this.fromGeometry( geometry ); + } else { - } + intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); - } + } - return this; + if ( intersect === null ) { return null; } - }, + _intersectionPointWorld.copy( point ); + _intersectionPointWorld.applyMatrix4( object.matrixWorld ); - setFromPoints: function ( points ) { + var distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); - var position = []; + if ( distance < raycaster.near || distance > raycaster.far ) { return null; } - for ( var i = 0, l = points.length; i < l; i ++ ) { + return { + distance: distance, + point: _intersectionPointWorld.clone(), + object: object + }; - var point = points[ i ]; - position.push( point.x, point.y, point.z || 0 ); + } - } + function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) { - this.addAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); + _vA.fromBufferAttribute( position, a ); + _vB.fromBufferAttribute( position, b ); + _vC.fromBufferAttribute( position, c ); - return this; + var morphInfluences = object.morphTargetInfluences; - }, + if ( material.morphTargets && morphPosition && morphInfluences ) { - updateFromObject: function ( object ) { + _morphA.set( 0, 0, 0 ); + _morphB.set( 0, 0, 0 ); + _morphC.set( 0, 0, 0 ); - var geometry = object.geometry; + for ( var i = 0, il = morphPosition.length; i < il; i ++ ) { - if ( object.isMesh ) { + var influence = morphInfluences[ i ]; + var morphAttribute = morphPosition[ i ]; - var direct = geometry.__directGeometry; + if ( influence === 0 ) { continue; } - if ( geometry.elementsNeedUpdate === true ) { + _tempA.fromBufferAttribute( morphAttribute, a ); + _tempB.fromBufferAttribute( morphAttribute, b ); + _tempC.fromBufferAttribute( morphAttribute, c ); - direct = undefined; - geometry.elementsNeedUpdate = false; + if ( morphTargetsRelative ) { - } + _morphA.addScaledVector( _tempA, influence ); + _morphB.addScaledVector( _tempB, influence ); + _morphC.addScaledVector( _tempC, influence ); - if ( direct === undefined ) { + } else { - return this.fromGeometry( geometry ); + _morphA.addScaledVector( _tempA.sub( _vA ), influence ); + _morphB.addScaledVector( _tempB.sub( _vB ), influence ); + _morphC.addScaledVector( _tempC.sub( _vC ), influence ); } - direct.verticesNeedUpdate = geometry.verticesNeedUpdate; - direct.normalsNeedUpdate = geometry.normalsNeedUpdate; - direct.colorsNeedUpdate = geometry.colorsNeedUpdate; - direct.uvsNeedUpdate = geometry.uvsNeedUpdate; - direct.groupsNeedUpdate = geometry.groupsNeedUpdate; + } - geometry.verticesNeedUpdate = false; - geometry.normalsNeedUpdate = false; - geometry.colorsNeedUpdate = false; - geometry.uvsNeedUpdate = false; - geometry.groupsNeedUpdate = false; + _vA.add( _morphA ); + _vB.add( _morphB ); + _vC.add( _morphC ); - geometry = direct; + } - } + if ( object.isSkinnedMesh ) { - var attribute; + object.boneTransform( a, _vA ); + object.boneTransform( b, _vB ); + object.boneTransform( c, _vC ); - if ( geometry.verticesNeedUpdate === true ) { + } - attribute = this.attributes.position; + var intersection = checkIntersection( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint ); - if ( attribute !== undefined ) { + if ( intersection ) { - attribute.copyVector3sArray( geometry.vertices ); - attribute.needsUpdate = true; + if ( uv ) { - } + _uvA.fromBufferAttribute( uv, a ); + _uvB.fromBufferAttribute( uv, b ); + _uvC.fromBufferAttribute( uv, c ); - geometry.verticesNeedUpdate = false; + intersection.uv = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ); } - if ( geometry.normalsNeedUpdate === true ) { + if ( uv2 ) { - attribute = this.attributes.normal; + _uvA.fromBufferAttribute( uv2, a ); + _uvB.fromBufferAttribute( uv2, b ); + _uvC.fromBufferAttribute( uv2, c ); - if ( attribute !== undefined ) { + intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ); - attribute.copyVector3sArray( geometry.normals ); - attribute.needsUpdate = true; + } - } + var face = new Face3( a, b, c ); + Triangle.getNormal( _vA, _vB, _vC, face.normal ); - geometry.normalsNeedUpdate = false; + intersection.face = face; - } + } - if ( geometry.colorsNeedUpdate === true ) { + return intersection; - attribute = this.attributes.color; + } - if ( attribute !== undefined ) { + var _geometryId = 0; // Geometry uses even numbers as Id + var _m1$3 = new Matrix4(); + var _obj$1 = new Object3D(); + var _offset$1 = new Vector3(); - attribute.copyColorsArray( geometry.colors ); - attribute.needsUpdate = true; + function Geometry() { - } + Object.defineProperty( this, 'id', { value: _geometryId += 2 } ); - geometry.colorsNeedUpdate = false; + this.uuid = MathUtils.generateUUID(); - } + this.name = ''; + this.type = 'Geometry'; - if ( geometry.uvsNeedUpdate ) { + this.vertices = []; + this.colors = []; + this.faces = []; + this.faceVertexUvs = [[]]; - attribute = this.attributes.uv; + this.morphTargets = []; + this.morphNormals = []; - if ( attribute !== undefined ) { + this.skinWeights = []; + this.skinIndices = []; - attribute.copyVector2sArray( geometry.uvs ); - attribute.needsUpdate = true; + this.lineDistances = []; - } + this.boundingBox = null; + this.boundingSphere = null; - geometry.uvsNeedUpdate = false; - - } - - if ( geometry.lineDistancesNeedUpdate ) { + // update flags - attribute = this.attributes.lineDistance; + this.elementsNeedUpdate = false; + this.verticesNeedUpdate = false; + this.uvsNeedUpdate = false; + this.normalsNeedUpdate = false; + this.colorsNeedUpdate = false; + this.lineDistancesNeedUpdate = false; + this.groupsNeedUpdate = false; - if ( attribute !== undefined ) { + } - attribute.copyArray( geometry.lineDistances ); - attribute.needsUpdate = true; + Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - } + constructor: Geometry, - geometry.lineDistancesNeedUpdate = false; + isGeometry: true, - } + applyMatrix4: function ( matrix ) { - if ( geometry.groupsNeedUpdate ) { + var normalMatrix = new Matrix3().getNormalMatrix( matrix ); - geometry.computeGroups( object.geometry ); - this.groups = geometry.groups; + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { - geometry.groupsNeedUpdate = false; + var vertex = this.vertices[ i ]; + vertex.applyMatrix4( matrix ); } - return this; + for ( var i$1 = 0, il$1 = this.faces.length; i$1 < il$1; i$1 ++ ) { - }, + var face = this.faces[ i$1 ]; + face.normal.applyMatrix3( normalMatrix ).normalize(); - fromGeometry: function ( geometry ) { + for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { - geometry.__directGeometry = new DirectGeometry().fromGeometry( geometry ); + face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); - return this.fromDirectGeometry( geometry.__directGeometry ); + } - }, + } - fromDirectGeometry: function ( geometry ) { + if ( this.boundingBox !== null ) { - var positions = new Float32Array( geometry.vertices.length * 3 ); - this.addAttribute( 'position', new BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) ); + this.computeBoundingBox(); - if ( geometry.normals.length > 0 ) { + } - var normals = new Float32Array( geometry.normals.length * 3 ); - this.addAttribute( 'normal', new BufferAttribute( normals, 3 ).copyVector3sArray( geometry.normals ) ); + if ( this.boundingSphere !== null ) { + + this.computeBoundingSphere(); } - if ( geometry.colors.length > 0 ) { + this.verticesNeedUpdate = true; + this.normalsNeedUpdate = true; - var colors = new Float32Array( geometry.colors.length * 3 ); - this.addAttribute( 'color', new BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) ); + return this; - } + }, - if ( geometry.uvs.length > 0 ) { + rotateX: function ( angle ) { - var uvs = new Float32Array( geometry.uvs.length * 2 ); - this.addAttribute( 'uv', new BufferAttribute( uvs, 2 ).copyVector2sArray( geometry.uvs ) ); + // rotate geometry around world x-axis - } + _m1$3.makeRotationX( angle ); - if ( geometry.uvs2.length > 0 ) { + this.applyMatrix4( _m1$3 ); - var uvs2 = new Float32Array( geometry.uvs2.length * 2 ); - this.addAttribute( 'uv2', new BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) ); + return this; - } + }, - // groups + rotateY: function ( angle ) { - this.groups = geometry.groups; + // rotate geometry around world y-axis - // morphs + _m1$3.makeRotationY( angle ); - for ( var name in geometry.morphTargets ) { + this.applyMatrix4( _m1$3 ); - var array = []; - var morphTargets = geometry.morphTargets[ name ]; + return this; - for ( var i = 0, l = morphTargets.length; i < l; i ++ ) { + }, - var morphTarget = morphTargets[ i ]; + rotateZ: function ( angle ) { - var attribute = new Float32BufferAttribute( morphTarget.data.length * 3, 3 ); - attribute.name = morphTarget.name; + // rotate geometry around world z-axis - array.push( attribute.copyVector3sArray( morphTarget.data ) ); + _m1$3.makeRotationZ( angle ); - } + this.applyMatrix4( _m1$3 ); - this.morphAttributes[ name ] = array; + return this; - } + }, - // skinning + translate: function ( x, y, z ) { - if ( geometry.skinIndices.length > 0 ) { + // translate geometry - var skinIndices = new Float32BufferAttribute( geometry.skinIndices.length * 4, 4 ); - this.addAttribute( 'skinIndex', skinIndices.copyVector4sArray( geometry.skinIndices ) ); + _m1$3.makeTranslation( x, y, z ); - } + this.applyMatrix4( _m1$3 ); - if ( geometry.skinWeights.length > 0 ) { + return this; - var skinWeights = new Float32BufferAttribute( geometry.skinWeights.length * 4, 4 ); - this.addAttribute( 'skinWeight', skinWeights.copyVector4sArray( geometry.skinWeights ) ); + }, - } + scale: function ( x, y, z ) { - // + // scale geometry - if ( geometry.boundingSphere !== null ) { + _m1$3.makeScale( x, y, z ); - this.boundingSphere = geometry.boundingSphere.clone(); + this.applyMatrix4( _m1$3 ); - } + return this; - if ( geometry.boundingBox !== null ) { + }, - this.boundingBox = geometry.boundingBox.clone(); + lookAt: function ( vector ) { - } + _obj$1.lookAt( vector ); + + _obj$1.updateMatrix(); + + this.applyMatrix4( _obj$1.matrix ); return this; }, - computeBoundingBox: function () { + fromBufferGeometry: function ( geometry ) { - if ( this.boundingBox === null ) { + var scope = this; - this.boundingBox = new Box3(); + var index = geometry.index !== null ? geometry.index : undefined; + var attributes = geometry.attributes; + + if ( attributes.position === undefined ) { + + console.error( 'THREE.Geometry.fromBufferGeometry(): Position attribute required for conversion.' ); + return this; } - var position = this.attributes.position; + var position = attributes.position; + var normal = attributes.normal; + var color = attributes.color; + var uv = attributes.uv; + var uv2 = attributes.uv2; - if ( position !== undefined ) { + if ( uv2 !== undefined ) { this.faceVertexUvs[ 1 ] = []; } - this.boundingBox.setFromBufferAttribute( position ); + for ( var i = 0; i < position.count; i ++ ) { - } else { + scope.vertices.push( new Vector3().fromBufferAttribute( position, i ) ); - this.boundingBox.makeEmpty(); + if ( color !== undefined ) { + + scope.colors.push( new Color().fromBufferAttribute( color, i ) ); + + } } - if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { + function addFace( a, b, c, materialIndex ) { - console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); + var vertexColors = ( color === undefined ) ? [] : [ + scope.colors[ a ].clone(), + scope.colors[ b ].clone(), + scope.colors[ c ].clone() + ]; - } + var vertexNormals = ( normal === undefined ) ? [] : [ + new Vector3().fromBufferAttribute( normal, a ), + new Vector3().fromBufferAttribute( normal, b ), + new Vector3().fromBufferAttribute( normal, c ) + ]; - }, + var face = new Face3( a, b, c, vertexNormals, vertexColors, materialIndex ); - computeBoundingSphere: function () { + scope.faces.push( face ); - var box = new Box3(); - var vector = new Vector3(); + if ( uv !== undefined ) { - return function computeBoundingSphere() { + scope.faceVertexUvs[ 0 ].push( [ + new Vector2().fromBufferAttribute( uv, a ), + new Vector2().fromBufferAttribute( uv, b ), + new Vector2().fromBufferAttribute( uv, c ) + ] ); + + } - if ( this.boundingSphere === null ) { + if ( uv2 !== undefined ) { - this.boundingSphere = new Sphere(); + scope.faceVertexUvs[ 1 ].push( [ + new Vector2().fromBufferAttribute( uv2, a ), + new Vector2().fromBufferAttribute( uv2, b ), + new Vector2().fromBufferAttribute( uv2, c ) + ] ); } - var position = this.attributes.position; + } - if ( position ) { + var groups = geometry.groups; - var center = this.boundingSphere.center; + if ( groups.length > 0 ) { - box.setFromBufferAttribute( position ); - box.getCenter( center ); + for ( var i$1 = 0; i$1 < groups.length; i$1 ++ ) { - // hoping to find a boundingSphere with a radius smaller than the - // boundingSphere of the boundingBox: sqrt(3) smaller in the best case + var group = groups[ i$1 ]; - var maxRadiusSq = 0; + var start = group.start; + var count = group.count; - for ( var i = 0, il = position.count; i < il; i ++ ) { + for ( var j = start, jl = start + count; j < jl; j += 3 ) { - vector.x = position.getX( i ); - vector.y = position.getY( i ); - vector.z = position.getZ( i ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + if ( index !== undefined ) { - } + addFace( index.getX( j ), index.getX( j + 1 ), index.getX( j + 2 ), group.materialIndex ); - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + } else { - if ( isNaN( this.boundingSphere.radius ) ) { + addFace( j, j + 1, j + 2, group.materialIndex ); - console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); + } } } - }; - - }(), + } else { - computeFaceNormals: function () { + if ( index !== undefined ) { - // backwards compatibility + for ( var i$2 = 0; i$2 < index.count; i$2 += 3 ) { - }, + addFace( index.getX( i$2 ), index.getX( i$2 + 1 ), index.getX( i$2 + 2 ) ); - computeVertexNormals: function () { + } - var index = this.index; - var attributes = this.attributes; + } else { - if ( attributes.position ) { + for ( var i$3 = 0; i$3 < position.count; i$3 += 3 ) { - var positions = attributes.position.array; + addFace( i$3, i$3 + 1, i$3 + 2 ); - if ( attributes.normal === undefined ) { + } - this.addAttribute( 'normal', new BufferAttribute( new Float32Array( positions.length ), 3 ) ); + } - } else { + } - // reset existing normals to zero + this.computeFaceNormals(); - var array = attributes.normal.array; + if ( geometry.boundingBox !== null ) { - for ( var i = 0, il = array.length; i < il; i ++ ) { + this.boundingBox = geometry.boundingBox.clone(); - array[ i ] = 0; + } - } + if ( geometry.boundingSphere !== null ) { - } + this.boundingSphere = geometry.boundingSphere.clone(); - var normals = attributes.normal.array; + } - var vA, vB, vC; - var pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); - var cb = new Vector3(), ab = new Vector3(); + return this; - // indexed elements + }, - if ( index ) { + center: function () { - var indices = index.array; + this.computeBoundingBox(); - for ( var i = 0, il = index.count; i < il; i += 3 ) { + this.boundingBox.getCenter( _offset$1 ).negate(); - vA = indices[ i + 0 ] * 3; - vB = indices[ i + 1 ] * 3; - vC = indices[ i + 2 ] * 3; + this.translate( _offset$1.x, _offset$1.y, _offset$1.z ); - pA.fromArray( positions, vA ); - pB.fromArray( positions, vB ); - pC.fromArray( positions, vC ); + return this; - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + }, - normals[ vA ] += cb.x; - normals[ vA + 1 ] += cb.y; - normals[ vA + 2 ] += cb.z; + normalize: function () { - normals[ vB ] += cb.x; - normals[ vB + 1 ] += cb.y; - normals[ vB + 2 ] += cb.z; + this.computeBoundingSphere(); - normals[ vC ] += cb.x; - normals[ vC + 1 ] += cb.y; - normals[ vC + 2 ] += cb.z; + var center = this.boundingSphere.center; + var radius = this.boundingSphere.radius; - } + var s = radius === 0 ? 1 : 1.0 / radius; - } else { + var matrix = new Matrix4(); + matrix.set( + s, 0, 0, - s * center.x, + 0, s, 0, - s * center.y, + 0, 0, s, - s * center.z, + 0, 0, 0, 1 + ); - // non-indexed elements (unconnected triangle soup) + this.applyMatrix4( matrix ); - for ( var i = 0, il = positions.length; i < il; i += 9 ) { + return this; - pA.fromArray( positions, i ); - pB.fromArray( positions, i + 3 ); - pC.fromArray( positions, i + 6 ); + }, - cb.subVectors( pC, pB ); - ab.subVectors( pA, pB ); - cb.cross( ab ); + computeFaceNormals: function () { - normals[ i ] = cb.x; - normals[ i + 1 ] = cb.y; - normals[ i + 2 ] = cb.z; + var cb = new Vector3(), ab = new Vector3(); - normals[ i + 3 ] = cb.x; - normals[ i + 4 ] = cb.y; - normals[ i + 5 ] = cb.z; + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - normals[ i + 6 ] = cb.x; - normals[ i + 7 ] = cb.y; - normals[ i + 8 ] = cb.z; + var face = this.faces[ f ]; - } + var vA = this.vertices[ face.a ]; + var vB = this.vertices[ face.b ]; + var vC = this.vertices[ face.c ]; - } + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); - this.normalizeNormals(); + cb.normalize(); - attributes.normal.needsUpdate = true; + face.normal.copy( cb ); } }, - merge: function ( geometry, offset ) { - - if ( ! ( geometry && geometry.isBufferGeometry ) ) { - - console.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry ); - return; + computeVertexNormals: function ( areaWeighted ) { - } + if ( areaWeighted === undefined ) { areaWeighted = true; } - if ( offset === undefined ) { + var vertices = new Array( this.vertices.length ); - offset = 0; + for ( var v = 0, vl = this.vertices.length; v < vl; v ++ ) { - console.warn( - 'THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. ' - + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.' - ); + vertices[ v ] = new Vector3(); } - var attributes = this.attributes; + if ( areaWeighted ) { - for ( var key in attributes ) { + // vertex normals weighted by triangle areas + // http://www.iquilezles.org/www/articles/normals/normals.htm - if ( geometry.attributes[ key ] === undefined ) continue; + var cb = new Vector3(), ab = new Vector3(); - var attribute1 = attributes[ key ]; - var attributeArray1 = attribute1.array; + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - var attribute2 = geometry.attributes[ key ]; - var attributeArray2 = attribute2.array; + var face = this.faces[ f ]; - var attributeSize = attribute2.itemSize; + var vA = this.vertices[ face.a ]; + var vB = this.vertices[ face.b ]; + var vC = this.vertices[ face.c ]; - for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) { + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ); - attributeArray1[ j ] = attributeArray2[ i ]; + vertices[ face.a ].add( cb ); + vertices[ face.b ].add( cb ); + vertices[ face.c ].add( cb ); } - } + } else { - return this; + this.computeFaceNormals(); - }, + for ( var f$1 = 0, fl$1 = this.faces.length; f$1 < fl$1; f$1 ++ ) { - normalizeNormals: function () { + var face$1 = this.faces[ f$1 ]; - var vector = new Vector3(); + vertices[ face$1.a ].add( face$1.normal ); + vertices[ face$1.b ].add( face$1.normal ); + vertices[ face$1.c ].add( face$1.normal ); + + } - return function normalizeNormals() { + } - var normals = this.attributes.normal; + for ( var v$1 = 0, vl$1 = this.vertices.length; v$1 < vl$1; v$1 ++ ) { - for ( var i = 0, il = normals.count; i < il; i ++ ) { + vertices[ v$1 ].normalize(); - vector.x = normals.getX( i ); - vector.y = normals.getY( i ); - vector.z = normals.getZ( i ); + } - vector.normalize(); + for ( var f$2 = 0, fl$2 = this.faces.length; f$2 < fl$2; f$2 ++ ) { - normals.setXYZ( i, vector.x, vector.y, vector.z ); + var face$2 = this.faces[ f$2 ]; - } + var vertexNormals = face$2.vertexNormals; - }; + if ( vertexNormals.length === 3 ) { - }(), + vertexNormals[ 0 ].copy( vertices[ face$2.a ] ); + vertexNormals[ 1 ].copy( vertices[ face$2.b ] ); + vertexNormals[ 2 ].copy( vertices[ face$2.c ] ); - toNonIndexed: function () { + } else { - if ( this.index === null ) { + vertexNormals[ 0 ] = vertices[ face$2.a ].clone(); + vertexNormals[ 1 ] = vertices[ face$2.b ].clone(); + vertexNormals[ 2 ] = vertices[ face$2.c ].clone(); - console.warn( 'THREE.BufferGeometry.toNonIndexed(): Geometry is already non-indexed.' ); - return this; + } } - var geometry2 = new BufferGeometry(); + if ( this.faces.length > 0 ) { - var indices = this.index.array; - var attributes = this.attributes; + this.normalsNeedUpdate = true; - for ( var name in attributes ) { + } - var attribute = attributes[ name ]; + }, - var array = attribute.array; - var itemSize = attribute.itemSize; + computeFlatVertexNormals: function () { - var array2 = new array.constructor( indices.length * itemSize ); + this.computeFaceNormals(); - var index = 0, index2 = 0; + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - for ( var i = 0, l = indices.length; i < l; i ++ ) { + var face = this.faces[ f ]; - index = indices[ i ] * itemSize; + var vertexNormals = face.vertexNormals; - for ( var j = 0; j < itemSize; j ++ ) { + if ( vertexNormals.length === 3 ) { - array2[ index2 ++ ] = array[ index ++ ]; + vertexNormals[ 0 ].copy( face.normal ); + vertexNormals[ 1 ].copy( face.normal ); + vertexNormals[ 2 ].copy( face.normal ); - } + } else { - } + vertexNormals[ 0 ] = face.normal.clone(); + vertexNormals[ 1 ] = face.normal.clone(); + vertexNormals[ 2 ] = face.normal.clone(); - geometry2.addAttribute( name, new BufferAttribute( array2, itemSize ) ); + } } - var groups = this.groups; - - for ( var i = 0, l = groups.length; i < l; i ++ ) { + if ( this.faces.length > 0 ) { - var group = groups[ i ]; - geometry2.addGroup( group.start, group.count, group.materialIndex ); + this.normalsNeedUpdate = true; } - return geometry2; - }, - toJSON: function () { + computeMorphNormals: function () { - var data = { - metadata: { - version: 4.5, - type: 'BufferGeometry', - generator: 'BufferGeometry.toJSON' - } - }; + // save original normals + // - create temp variables on first access + // otherwise just copy (for faster repeated calls) - // standard BufferGeometry serialization + for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { - 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; + var face = this.faces[ f ]; - if ( this.parameters !== undefined ) { + if ( ! face.__originalFaceNormal ) { - var parameters = this.parameters; + face.__originalFaceNormal = face.normal.clone(); - for ( var key in parameters ) { + } else { - if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; + face.__originalFaceNormal.copy( face.normal ); } - return data; + if ( ! face.__originalVertexNormals ) { face.__originalVertexNormals = []; } - } + for ( var i = 0, il = face.vertexNormals.length; i < il; i ++ ) { - data.data = { attributes: {} }; + if ( ! face.__originalVertexNormals[ i ] ) { - var index = this.index; + face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); - if ( index !== null ) { + } else { - var array = Array.prototype.slice.call( index.array ); + face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); - data.data.index = { - type: index.array.constructor.name, - array: array - }; + } + + } } - var attributes = this.attributes; + // use temp geometry to compute face and vertex normals for each morph - for ( var key in attributes ) { + var tmpGeo = new Geometry(); + tmpGeo.faces = this.faces; - var attribute = attributes[ key ]; + for ( var i$1 = 0, il$1 = this.morphTargets.length; i$1 < il$1; i$1 ++ ) { - var array = Array.prototype.slice.call( attribute.array ); + // create on first access - data.data.attributes[ key ] = { - itemSize: attribute.itemSize, - type: attribute.array.constructor.name, - array: array, - normalized: attribute.normalized - }; + if ( ! this.morphNormals[ i$1 ] ) { - } + this.morphNormals[ i$1 ] = {}; + this.morphNormals[ i$1 ].faceNormals = []; + this.morphNormals[ i$1 ].vertexNormals = []; - var groups = this.groups; + var dstNormalsFace = this.morphNormals[ i$1 ].faceNormals; + var dstNormalsVertex = this.morphNormals[ i$1 ].vertexNormals; - if ( groups.length > 0 ) { + for ( var f$1 = 0, fl$1 = this.faces.length; f$1 < fl$1; f$1 ++ ) { - data.data.groups = JSON.parse( JSON.stringify( groups ) ); + var faceNormal = new Vector3(); + var vertexNormals = { a: new Vector3(), b: new Vector3(), c: new Vector3() }; - } + dstNormalsFace.push( faceNormal ); + dstNormalsVertex.push( vertexNormals ); - var boundingSphere = this.boundingSphere; + } - if ( boundingSphere !== null ) { + } - data.data.boundingSphere = { - center: boundingSphere.center.toArray(), - radius: boundingSphere.radius - }; + var morphNormals = this.morphNormals[ i$1 ]; - } + // set vertices to morph target - return data; + tmpGeo.vertices = this.morphTargets[ i$1 ].vertices; - }, + // compute morph normals - clone: function () { + tmpGeo.computeFaceNormals(); + tmpGeo.computeVertexNormals(); - /* - // Handle primitives + // store morph normals - var parameters = this.parameters; + for ( var f$2 = 0, fl$2 = this.faces.length; f$2 < fl$2; f$2 ++ ) { - if ( parameters !== undefined ) { + var face$1 = this.faces[ f$2 ]; - var values = []; + var faceNormal$1 = morphNormals.faceNormals[ f$2 ]; + var vertexNormals$1 = morphNormals.vertexNormals[ f$2 ]; - for ( var key in parameters ) { + faceNormal$1.copy( face$1.normal ); - values.push( parameters[ key ] ); + vertexNormals$1.a.copy( face$1.vertexNormals[ 0 ] ); + vertexNormals$1.b.copy( face$1.vertexNormals[ 1 ] ); + vertexNormals$1.c.copy( face$1.vertexNormals[ 2 ] ); - } + } - var geometry = Object.create( this.constructor.prototype ); - this.constructor.apply( geometry, values ); - return geometry; + } - } + // restore original normals - return new this.constructor().copy( this ); - */ + for ( var f$3 = 0, fl$3 = this.faces.length; f$3 < fl$3; f$3 ++ ) { - return new BufferGeometry().copy( this ); + var face$2 = this.faces[ f$3 ]; - }, + face$2.normal = face$2.__originalFaceNormal; + face$2.vertexNormals = face$2.__originalVertexNormals; - copy: function ( source ) { + } - var name, i, l; + }, - // reset + computeBoundingBox: function () { - this.index = null; - this.attributes = {}; - this.morphAttributes = {}; - this.groups = []; - this.boundingBox = null; - this.boundingSphere = null; + if ( this.boundingBox === null ) { - // name + this.boundingBox = new Box3(); - this.name = source.name; + } - // index + this.boundingBox.setFromPoints( this.vertices ); - var index = source.index; + }, - if ( index !== null ) { + computeBoundingSphere: function () { - this.setIndex( index.clone() ); + if ( this.boundingSphere === null ) { - } + this.boundingSphere = new Sphere(); - // attributes + } - var attributes = source.attributes; + this.boundingSphere.setFromPoints( this.vertices ); - for ( name in attributes ) { + }, - var attribute = attributes[ name ]; - this.addAttribute( name, attribute.clone() ); + merge: function ( geometry, matrix, materialIndexOffset ) { - } + if ( ! ( geometry && geometry.isGeometry ) ) { - // morph attributes + console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry ); + return; - var morphAttributes = source.morphAttributes; + } - for ( name in morphAttributes ) { + var normalMatrix, + vertexOffset = this.vertices.length, + vertices1 = this.vertices, + vertices2 = geometry.vertices, + faces1 = this.faces, + faces2 = geometry.faces, + colors1 = this.colors, + colors2 = geometry.colors; - var array = []; - var morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes + if ( materialIndexOffset === undefined ) { materialIndexOffset = 0; } - for ( i = 0, l = morphAttribute.length; i < l; i ++ ) { + if ( matrix !== undefined ) { - array.push( morphAttribute[ i ].clone() ); + normalMatrix = new Matrix3().getNormalMatrix( matrix ); - } + } - this.morphAttributes[ name ] = array; + // vertices - } + for ( var i = 0, il = vertices2.length; i < il; i ++ ) { - // groups + var vertex = vertices2[ i ]; - var groups = source.groups; + var vertexCopy = vertex.clone(); - for ( i = 0, l = groups.length; i < l; i ++ ) { + if ( matrix !== undefined ) { vertexCopy.applyMatrix4( matrix ); } - var group = groups[ i ]; - this.addGroup( group.start, group.count, group.materialIndex ); + vertices1.push( vertexCopy ); } - // bounding box - - var boundingBox = source.boundingBox; + // colors - if ( boundingBox !== null ) { + for ( var i$1 = 0, il$1 = colors2.length; i$1 < il$1; i$1 ++ ) { - this.boundingBox = boundingBox.clone(); + colors1.push( colors2[ i$1 ].clone() ); } - // bounding sphere + // faces - var boundingSphere = source.boundingSphere; + for ( var i$2 = 0, il$2 = faces2.length; i$2 < il$2; i$2 ++ ) { - if ( boundingSphere !== null ) { + var face = faces2[ i$2 ], faceCopy = (void 0), normal = (void 0), color = (void 0), + faceVertexNormals = face.vertexNormals, + faceVertexColors = face.vertexColors; - this.boundingSphere = boundingSphere.clone(); + faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); + faceCopy.normal.copy( face.normal ); - } + if ( normalMatrix !== undefined ) { - // draw range + faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); - this.drawRange.start = source.drawRange.start; - this.drawRange.count = source.drawRange.count; + } - // user data + for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { - this.userData = source.userData; + normal = faceVertexNormals[ j ].clone(); - return this; + if ( normalMatrix !== undefined ) { - }, + normal.applyMatrix3( normalMatrix ).normalize(); - dispose: function () { + } - this.dispatchEvent( { type: 'dispose' } ); + faceCopy.vertexNormals.push( normal ); - } + } - } ); + faceCopy.color.copy( face.color ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + for ( var j$1 = 0, jl$1 = faceVertexColors.length; j$1 < jl$1; j$1 ++ ) { - // BoxGeometry - - function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { - - Geometry.call( this ); + color = faceVertexColors[ j$1 ]; + faceCopy.vertexColors.push( color.clone() ); - this.type = 'BoxGeometry'; + } - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; + faceCopy.materialIndex = face.materialIndex + materialIndexOffset; - this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) ); - this.mergeVertices(); + faces1.push( faceCopy ); - } + } - BoxGeometry.prototype = Object.create( Geometry.prototype ); - BoxGeometry.prototype.constructor = BoxGeometry; + // uvs - // BoxBufferGeometry + for ( var i$3 = 0, il$3 = geometry.faceVertexUvs.length; i$3 < il$3; i$3 ++ ) { - function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { + var faceVertexUvs2 = geometry.faceVertexUvs[ i$3 ]; - BufferGeometry.call( this ); + if ( this.faceVertexUvs[ i$3 ] === undefined ) { this.faceVertexUvs[ i$3 ] = []; } - this.type = 'BoxBufferGeometry'; + for ( var j$2 = 0, jl$2 = faceVertexUvs2.length; j$2 < jl$2; j$2 ++ ) { - this.parameters = { - width: width, - height: height, - depth: depth, - widthSegments: widthSegments, - heightSegments: heightSegments, - depthSegments: depthSegments - }; + var uvs2 = faceVertexUvs2[ j$2 ], uvsCopy = []; - var scope = this; + for ( var k = 0, kl = uvs2.length; k < kl; k ++ ) { - width = width || 1; - height = height || 1; - depth = depth || 1; + uvsCopy.push( uvs2[ k ].clone() ); - // segments + } - widthSegments = Math.floor( widthSegments ) || 1; - heightSegments = Math.floor( heightSegments ) || 1; - depthSegments = Math.floor( depthSegments ) || 1; + this.faceVertexUvs[ i$3 ].push( uvsCopy ); - // buffers + } - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + } - // helper variables + }, - var numberOfVertices = 0; - var groupStart = 0; + mergeMesh: function ( mesh ) { - // build each side of the box geometry + if ( ! ( mesh && mesh.isMesh ) ) { - 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 + console.error( 'THREE.Geometry.mergeMesh(): mesh not an instance of THREE.Mesh.', mesh ); + return; - // build geometry + } - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + if ( mesh.matrixAutoUpdate ) { mesh.updateMatrix(); } - function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { + this.merge( mesh.geometry, mesh.matrix ); - var segmentWidth = width / gridX; - var segmentHeight = height / gridY; + }, - var widthHalf = width / 2; - var heightHalf = height / 2; - var depthHalf = depth / 2; + /* + * Checks for duplicate vertices with hashmap. + * Duplicated vertices are removed + * and faces' vertices are updated. + */ - var gridX1 = gridX + 1; - var gridY1 = gridY + 1; + mergeVertices: function () { - var vertexCounter = 0; - var groupCount = 0; + var verticesMap = {}; // Hashmap for looking up vertices by position coordinates (and making sure they are unique) + var unique = [], changes = []; - var ix, iy; + var precisionPoints = 4; // number of decimal points, e.g. 4 for epsilon of 0.0001 + var precision = Math.pow( 10, precisionPoints ); - var vector = new Vector3(); + for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { - // generate vertices, normals and uvs + var v = this.vertices[ i ]; + var key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); - for ( iy = 0; iy < gridY1; iy ++ ) { + if ( verticesMap[ key ] === undefined ) { - var y = iy * segmentHeight - heightHalf; + verticesMap[ key ] = i; + unique.push( this.vertices[ i ] ); + changes[ i ] = unique.length - 1; - for ( ix = 0; ix < gridX1; ix ++ ) { + } else { - var x = ix * segmentWidth - widthHalf; + //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); + changes[ i ] = changes[ verticesMap[ key ] ]; - // 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 ); + // if faces are completely degenerate after merging vertices, we + // have to remove them from the geometry. + var faceIndicesToRemove = []; - // set values to correct vector component + for ( var i$1 = 0, il$1 = this.faces.length; i$1 < il$1; i$1 ++ ) { - vector[ u ] = 0; - vector[ v ] = 0; - vector[ w ] = depth > 0 ? 1 : - 1; + var face = this.faces[ i$1 ]; - // now apply vector to normal buffer + face.a = changes[ face.a ]; + face.b = changes[ face.b ]; + face.c = changes[ face.c ]; - normals.push( vector.x, vector.y, vector.z ); + var indices = [ face.a, face.b, face.c ]; - // uvs + // if any duplicate vertices are found in a Face3 + // we have to remove the face as nothing can be saved + for ( var n = 0; n < 3; n ++ ) { - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); + if ( indices[ n ] === indices[ ( n + 1 ) % 3 ] ) { - // counters + faceIndicesToRemove.push( i$1 ); + break; - vertexCounter += 1; + } } } - // indices + for ( var i$2 = faceIndicesToRemove.length - 1; i$2 >= 0; i$2 -- ) { - // 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 + var idx = faceIndicesToRemove[ i$2 ]; - for ( iy = 0; iy < gridY; iy ++ ) { + this.faces.splice( idx, 1 ); - for ( ix = 0; ix < gridX; ix ++ ) { + for ( var j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { - var a = numberOfVertices + ix + gridX1 * iy; - var b = numberOfVertices + ix + gridX1 * ( iy + 1 ); - var c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; + this.faceVertexUvs[ j ].splice( idx, 1 ); - // faces + } - indices.push( a, b, d ); - indices.push( b, c, d ); + } - // increase counter + // Use unique set of vertices - groupCount += 6; + var diff = this.vertices.length - unique.length; + this.vertices = unique; + return diff; - } + }, - } + setFromPoints: function ( points ) { - // add a group to the geometry. this will ensure multi material support + this.vertices = []; - scope.addGroup( groupStart, groupCount, materialIndex ); + for ( var i = 0, l = points.length; i < l; i ++ ) { - // calculate new start value for groups + var point = points[ i ]; + this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); - groupStart += groupCount; + } - // update total number of vertices + return this; - numberOfVertices += vertexCounter; + }, - } + sortFacesByMaterialIndex: function () { - } + var faces = this.faces; + var length = faces.length; - BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - BoxBufferGeometry.prototype.constructor = BoxBufferGeometry; + // tag faces - /** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + for ( var i = 0; i < length; i ++ ) { - // PlaneGeometry + faces[ i ]._id = i; - function PlaneGeometry( width, height, widthSegments, heightSegments ) { + } - Geometry.call( this ); + // sort faces - this.type = 'PlaneGeometry'; + function materialIndexSort( a, b ) { - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; + return a.materialIndex - b.materialIndex; - this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); - this.mergeVertices(); + } - } + faces.sort( materialIndexSort ); - PlaneGeometry.prototype = Object.create( Geometry.prototype ); - PlaneGeometry.prototype.constructor = PlaneGeometry; + // sort uvs - // PlaneBufferGeometry + var uvs1 = this.faceVertexUvs[ 0 ]; + var uvs2 = this.faceVertexUvs[ 1 ]; - function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) { + var newUvs1, newUvs2; - BufferGeometry.call( this ); + if ( uvs1 && uvs1.length === length ) { newUvs1 = []; } + if ( uvs2 && uvs2.length === length ) { newUvs2 = []; } - this.type = 'PlaneBufferGeometry'; + for ( var i$1 = 0; i$1 < length; i$1 ++ ) { - this.parameters = { - width: width, - height: height, - widthSegments: widthSegments, - heightSegments: heightSegments - }; + var id = faces[ i$1 ]._id; - width = width || 1; - height = height || 1; + if ( newUvs1 ) { newUvs1.push( uvs1[ id ] ); } + if ( newUvs2 ) { newUvs2.push( uvs2[ id ] ); } - var width_half = width / 2; - var height_half = height / 2; + } - var gridX = Math.floor( widthSegments ) || 1; - var gridY = Math.floor( heightSegments ) || 1; + if ( newUvs1 ) { this.faceVertexUvs[ 0 ] = newUvs1; } + if ( newUvs2 ) { this.faceVertexUvs[ 1 ] = newUvs2; } - var gridX1 = gridX + 1; - var gridY1 = gridY + 1; + }, - var segment_width = width / gridX; - var segment_height = height / gridY; + toJSON: function () { - var ix, iy; + var data = { + metadata: { + version: 4.5, + type: 'Geometry', + generator: 'Geometry.toJSON' + } + }; - // buffers + // standard Geometry serialization - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + data.uuid = this.uuid; + data.type = this.type; + if ( this.name !== '' ) { data.name = this.name; } - // generate vertices, normals and uvs + if ( this.parameters !== undefined ) { - for ( iy = 0; iy < gridY1; iy ++ ) { + var parameters = this.parameters; - var y = iy * segment_height - height_half; + for ( var key in parameters ) { - for ( ix = 0; ix < gridX1; ix ++ ) { + if ( parameters[ key ] !== undefined ) { data[ key ] = parameters[ key ]; } - var x = ix * segment_width - width_half; + } - vertices.push( x, - y, 0 ); + return data; - normals.push( 0, 0, 1 ); + } - uvs.push( ix / gridX ); - uvs.push( 1 - ( iy / gridY ) ); + var vertices = []; + + for ( var i = 0; i < this.vertices.length; i ++ ) { + + var vertex = this.vertices[ i ]; + vertices.push( vertex.x, vertex.y, vertex.z ); } - } + var faces = []; + var normals = []; + var normalsHash = {}; + var colors = []; + var colorsHash = {}; + var uvs = []; + var uvsHash = {}; - // indices + for ( var i$1 = 0; i$1 < this.faces.length; i$1 ++ ) { - for ( iy = 0; iy < gridY; iy ++ ) { + var face = this.faces[ i$1 ]; - for ( ix = 0; ix < gridX; ix ++ ) { + var hasMaterial = true; + var hasFaceUv = false; // deprecated + var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i$1 ] !== undefined; + var hasFaceNormal = face.normal.length() > 0; + var hasFaceVertexNormal = face.vertexNormals.length > 0; + var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1; + var hasFaceVertexColor = face.vertexColors.length > 0; - var a = ix + gridX1 * iy; - var b = ix + gridX1 * ( iy + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = ( ix + 1 ) + gridX1 * iy; + var faceType = 0; - // faces + faceType = setBit( faceType, 0, 0 ); // isQuad + faceType = setBit( faceType, 1, hasMaterial ); + faceType = setBit( faceType, 2, hasFaceUv ); + faceType = setBit( faceType, 3, hasFaceVertexUv ); + faceType = setBit( faceType, 4, hasFaceNormal ); + faceType = setBit( faceType, 5, hasFaceVertexNormal ); + faceType = setBit( faceType, 6, hasFaceColor ); + faceType = setBit( faceType, 7, hasFaceVertexColor ); - indices.push( a, b, d ); - indices.push( b, c, d ); + faces.push( faceType ); + faces.push( face.a, face.b, face.c ); + faces.push( face.materialIndex ); - } + if ( hasFaceVertexUv ) { - } + var faceVertexUvs = this.faceVertexUvs[ 0 ][ i$1 ]; - // build geometry + faces.push( + getUvIndex( faceVertexUvs[ 0 ] ), + getUvIndex( faceVertexUvs[ 1 ] ), + getUvIndex( faceVertexUvs[ 2 ] ) + ); - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + } - } + if ( hasFaceNormal ) { - PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry; + faces.push( getNormalIndex( face.normal ) ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + } - var materialId = 0; + if ( hasFaceVertexNormal ) { - function Material() { + var vertexNormals = face.vertexNormals; - Object.defineProperty( this, 'id', { value: materialId ++ } ); + faces.push( + getNormalIndex( vertexNormals[ 0 ] ), + getNormalIndex( vertexNormals[ 1 ] ), + getNormalIndex( vertexNormals[ 2 ] ) + ); - this.uuid = _Math.generateUUID(); + } - this.name = ''; - this.type = 'Material'; + if ( hasFaceColor ) { - this.fog = true; - this.lights = true; + faces.push( getColorIndex( face.color ) ); - this.blending = NormalBlending; - this.side = FrontSide; - this.flatShading = false; - this.vertexColors = NoColors; // THREE.NoColors, THREE.VertexColors, THREE.FaceColors + } - this.opacity = 1; - this.transparent = false; + if ( hasFaceVertexColor ) { - this.blendSrc = SrcAlphaFactor; - this.blendDst = OneMinusSrcAlphaFactor; - this.blendEquation = AddEquation; - this.blendSrcAlpha = null; - this.blendDstAlpha = null; - this.blendEquationAlpha = null; + var vertexColors = face.vertexColors; - this.depthFunc = LessEqualDepth; - this.depthTest = true; - this.depthWrite = true; + faces.push( + getColorIndex( vertexColors[ 0 ] ), + getColorIndex( vertexColors[ 1 ] ), + getColorIndex( vertexColors[ 2 ] ) + ); - this.clippingPlanes = null; - this.clipIntersection = false; - this.clipShadows = false; + } - this.shadowSide = null; + } - this.colorWrite = true; + function setBit( value, position, enabled ) { - this.precision = null; // override the renderer's default precision for this material + return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position ) ); - this.polygonOffset = false; - this.polygonOffsetFactor = 0; - this.polygonOffsetUnits = 0; + } - this.dithering = false; + function getNormalIndex( normal ) { - this.alphaTest = 0; - this.premultipliedAlpha = false; + var hash = normal.x.toString() + normal.y.toString() + normal.z.toString(); - this.visible = true; + if ( normalsHash[ hash ] !== undefined ) { - this.userData = {}; + return normalsHash[ hash ]; - this.needsUpdate = true; + } - } + normalsHash[ hash ] = normals.length / 3; + normals.push( normal.x, normal.y, normal.z ); - Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + return normalsHash[ hash ]; - constructor: Material, + } - isMaterial: true, + function getColorIndex( color ) { - onBeforeCompile: function () {}, + var hash = color.r.toString() + color.g.toString() + color.b.toString(); - setValues: function ( values ) { + if ( colorsHash[ hash ] !== undefined ) { - if ( values === undefined ) return; + return colorsHash[ hash ]; - for ( var key in values ) { + } - var newValue = values[ key ]; + colorsHash[ hash ] = colors.length; + colors.push( color.getHex() ); - if ( newValue === undefined ) { + return colorsHash[ hash ]; - console.warn( "THREE.Material: '" + key + "' parameter is undefined." ); - continue; + } - } + function getUvIndex( uv ) { - // for backward compatability if shading is set in the constructor - if ( key === 'shading' ) { + var hash = uv.x.toString() + uv.y.toString(); - console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); - this.flatShading = ( newValue === FlatShading ) ? true : false; - continue; + if ( uvsHash[ hash ] !== undefined ) { + + return uvsHash[ hash ]; } - var currentValue = this[ key ]; + uvsHash[ hash ] = uvs.length / 2; + uvs.push( uv.x, uv.y ); - if ( currentValue === undefined ) { + return uvsHash[ hash ]; - console.warn( "THREE." + this.type + ": '" + key + "' is not a property of this material." ); - continue; + } - } + data.data = {}; - if ( currentValue && currentValue.isColor ) { + data.data.vertices = vertices; + data.data.normals = normals; + if ( colors.length > 0 ) { data.data.colors = colors; } + if ( uvs.length > 0 ) { data.data.uvs = [ uvs ]; } // temporal backward compatibility + data.data.faces = faces; - currentValue.set( newValue ); + return data; - } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { + }, - currentValue.copy( newValue ); + clone: function () { - } else { + /* + // Handle primitives - this[ key ] = newValue; + const parameters = this.parameters; - } + if ( parameters !== undefined ) { - } + const values = []; - }, + for ( const key in parameters ) { - toJSON: function ( meta ) { + values.push( parameters[ key ] ); - var isRoot = ( meta === undefined || typeof meta === 'string' ); + } - if ( isRoot ) { + const geometry = Object.create( this.constructor.prototype ); + this.constructor.apply( geometry, values ); + return geometry; - meta = { - textures: {}, - images: {} - }; + } - } + return new this.constructor().copy( this ); + */ - var data = { - metadata: { - version: 4.5, - type: 'Material', - generator: 'Material.toJSON' - } - }; + return new Geometry().copy( this ); - // standard Material serialization - data.uuid = this.uuid; - data.type = this.type; + }, - if ( this.name !== '' ) data.name = this.name; + copy: function ( source ) { + + // reset - if ( this.color && this.color.isColor ) data.color = this.color.getHex(); + this.vertices = []; + this.colors = []; + this.faces = []; + this.faceVertexUvs = [[]]; + this.morphTargets = []; + this.morphNormals = []; + this.skinWeights = []; + this.skinIndices = []; + this.lineDistances = []; + this.boundingBox = null; + this.boundingSphere = null; - if ( this.roughness !== undefined ) data.roughness = this.roughness; - if ( this.metalness !== undefined ) data.metalness = this.metalness; + // name - if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); - if ( this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; + this.name = source.name; - if ( this.specular && this.specular.isColor ) data.specular = this.specular.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; + // vertices - if ( this.map && this.map.isTexture ) data.map = this.map.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; + var vertices = source.vertices; - if ( this.aoMap && this.aoMap.isTexture ) { + for ( var i = 0, il = vertices.length; i < il; i ++ ) { - data.aoMap = this.aoMap.toJSON( meta ).uuid; - data.aoMapIntensity = this.aoMapIntensity; + this.vertices.push( vertices[ i ].clone() ); } - if ( this.bumpMap && this.bumpMap.isTexture ) { + // colors - data.bumpMap = this.bumpMap.toJSON( meta ).uuid; - data.bumpScale = this.bumpScale; + var colors = source.colors; + + for ( var i$1 = 0, il$1 = colors.length; i$1 < il$1; i$1 ++ ) { + + this.colors.push( colors[ i$1 ].clone() ); } - if ( this.normalMap && this.normalMap.isTexture ) { + // faces - data.normalMap = this.normalMap.toJSON( meta ).uuid; - data.normalMapType = this.normalMapType; - data.normalScale = this.normalScale.toArray(); + var faces = source.faces; + + for ( var i$2 = 0, il$2 = faces.length; i$2 < il$2; i$2 ++ ) { + + this.faces.push( faces[ i$2 ].clone() ); } - if ( this.displacementMap && this.displacementMap.isTexture ) { + // face vertex uvs - data.displacementMap = this.displacementMap.toJSON( meta ).uuid; - data.displacementScale = this.displacementScale; - data.displacementBias = this.displacementBias; + for ( var i$3 = 0, il$3 = source.faceVertexUvs.length; i$3 < il$3; i$3 ++ ) { - } + var faceVertexUvs = source.faceVertexUvs[ i$3 ]; - 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.faceVertexUvs[ i$3 ] === undefined ) { - 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; + this.faceVertexUvs[ i$3 ] = []; - if ( this.envMap && this.envMap.isTexture ) { + } - data.envMap = this.envMap.toJSON( meta ).uuid; - data.reflectivity = this.reflectivity; // Scale behind envMap + for ( var j = 0, jl = faceVertexUvs.length; j < jl; j ++ ) { - if ( this.combine !== undefined ) data.combine = this.combine; - if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; + var uvs = faceVertexUvs[ j ], uvsCopy = []; - } + for ( var k = 0, kl = uvs.length; k < kl; k ++ ) { - if ( this.gradientMap && this.gradientMap.isTexture ) { + var uv = uvs[ k ]; - data.gradientMap = this.gradientMap.toJSON( meta ).uuid; + uvsCopy.push( uv.clone() ); + + } + + this.faceVertexUvs[ i$3 ].push( uvsCopy ); + + } } - if ( this.size !== undefined ) data.size = this.size; - if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; + // morph targets - if ( this.blending !== NormalBlending ) data.blending = this.blending; - if ( this.flatShading === true ) data.flatShading = this.flatShading; - if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors !== NoColors ) data.vertexColors = this.vertexColors; + var morphTargets = source.morphTargets; - if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = this.transparent; + for ( var i$4 = 0, il$4 = morphTargets.length; i$4 < il$4; i$4 ++ ) { - data.depthFunc = this.depthFunc; - data.depthTest = this.depthTest; - data.depthWrite = this.depthWrite; + var morphTarget = {}; + morphTarget.name = morphTargets[ i$4 ].name; - // rotation (SpriteMaterial) - if ( this.rotation !== 0 ) data.rotation = this.rotation; + // vertices - if ( this.polygonOffset === true ) data.polygonOffset = true; - if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; - if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; + if ( morphTargets[ i$4 ].vertices !== undefined ) { - if ( 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; + morphTarget.vertices = []; - if ( this.dithering === true ) data.dithering = true; + for ( var j$1 = 0, jl$1 = morphTargets[ i$4 ].vertices.length; j$1 < jl$1; j$1 ++ ) { - if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; + morphTarget.vertices.push( morphTargets[ i$4 ].vertices[ j$1 ].clone() ); - 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.morphTargets === true ) data.morphTargets = true; - if ( this.skinning === true ) data.skinning = true; + } - if ( this.visible === false ) data.visible = false; - if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; + // normals - // TODO: Copied from Object3D.toJSON + if ( morphTargets[ i$4 ].normals !== undefined ) { - function extractFromCache( cache ) { + morphTarget.normals = []; - var values = []; + for ( var j$2 = 0, jl$2 = morphTargets[ i$4 ].normals.length; j$2 < jl$2; j$2 ++ ) { - for ( var key in cache ) { + morphTarget.normals.push( morphTargets[ i$4 ].normals[ j$2 ].clone() ); - var data = cache[ key ]; - delete data.metadata; - values.push( data ); + } } - return values; + this.morphTargets.push( morphTarget ); } - if ( isRoot ) { + // morph normals - var textures = extractFromCache( meta.textures ); - var images = extractFromCache( meta.images ); + var morphNormals = source.morphNormals; - if ( textures.length > 0 ) data.textures = textures; - if ( images.length > 0 ) data.images = images; + for ( var i$5 = 0, il$5 = morphNormals.length; i$5 < il$5; i$5 ++ ) { - } + var morphNormal = {}; - return data; + // vertex normals - }, + if ( morphNormals[ i$5 ].vertexNormals !== undefined ) { - clone: function () { + morphNormal.vertexNormals = []; - return new this.constructor().copy( this ); + for ( var j$3 = 0, jl$3 = morphNormals[ i$5 ].vertexNormals.length; j$3 < jl$3; j$3 ++ ) { - }, + var srcVertexNormal = morphNormals[ i$5 ].vertexNormals[ j$3 ]; + var destVertexNormal = {}; - copy: function ( source ) { + destVertexNormal.a = srcVertexNormal.a.clone(); + destVertexNormal.b = srcVertexNormal.b.clone(); + destVertexNormal.c = srcVertexNormal.c.clone(); - this.name = source.name; + morphNormal.vertexNormals.push( destVertexNormal ); - this.fog = source.fog; - this.lights = source.lights; + } - this.blending = source.blending; - this.side = source.side; - this.flatShading = source.flatShading; - this.vertexColors = source.vertexColors; + } - this.opacity = source.opacity; - this.transparent = source.transparent; + // face normals - this.blendSrc = source.blendSrc; - this.blendDst = source.blendDst; - this.blendEquation = source.blendEquation; - this.blendSrcAlpha = source.blendSrcAlpha; - this.blendDstAlpha = source.blendDstAlpha; - this.blendEquationAlpha = source.blendEquationAlpha; + if ( morphNormals[ i$5 ].faceNormals !== undefined ) { - this.depthFunc = source.depthFunc; - this.depthTest = source.depthTest; - this.depthWrite = source.depthWrite; + morphNormal.faceNormals = []; - this.colorWrite = source.colorWrite; + for ( var j$4 = 0, jl$4 = morphNormals[ i$5 ].faceNormals.length; j$4 < jl$4; j$4 ++ ) { - this.precision = source.precision; + morphNormal.faceNormals.push( morphNormals[ i$5 ].faceNormals[ j$4 ].clone() ); - this.polygonOffset = source.polygonOffset; - this.polygonOffsetFactor = source.polygonOffsetFactor; - this.polygonOffsetUnits = source.polygonOffsetUnits; + } - this.dithering = source.dithering; + } - this.alphaTest = source.alphaTest; - this.premultipliedAlpha = source.premultipliedAlpha; + this.morphNormals.push( morphNormal ); - this.visible = source.visible; - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + } - this.clipShadows = source.clipShadows; - this.clipIntersection = source.clipIntersection; + // skin weights + + var skinWeights = source.skinWeights; - var srcPlanes = source.clippingPlanes, - dstPlanes = null; + for ( var i$6 = 0, il$6 = skinWeights.length; i$6 < il$6; i$6 ++ ) { - if ( srcPlanes !== null ) { + this.skinWeights.push( skinWeights[ i$6 ].clone() ); - var n = srcPlanes.length; - dstPlanes = new Array( n ); + } - for ( var i = 0; i !== n; ++ i ) - dstPlanes[ i ] = srcPlanes[ i ].clone(); + // skin indices + + var skinIndices = source.skinIndices; + + for ( var i$7 = 0, il$7 = skinIndices.length; i$7 < il$7; i$7 ++ ) { + + this.skinIndices.push( skinIndices[ i$7 ].clone() ); } - this.clippingPlanes = dstPlanes; + // line distances - this.shadowSide = source.shadowSide; + var lineDistances = source.lineDistances; + + for ( var i$8 = 0, il$8 = lineDistances.length; i$8 < il$8; i$8 ++ ) { + + this.lineDistances.push( lineDistances[ i$8 ] ); + + } + + // bounding box + + var boundingBox = source.boundingBox; + + if ( boundingBox !== null ) { + + this.boundingBox = boundingBox.clone(); + + } + + // bounding sphere + + var boundingSphere = source.boundingSphere; + + if ( boundingSphere !== null ) { + + this.boundingSphere = boundingSphere.clone(); + + } + + // update flags + + this.elementsNeedUpdate = source.elementsNeedUpdate; + this.verticesNeedUpdate = source.verticesNeedUpdate; + this.uvsNeedUpdate = source.uvsNeedUpdate; + this.normalsNeedUpdate = source.normalsNeedUpdate; + this.colorsNeedUpdate = source.colorsNeedUpdate; + this.lineDistancesNeedUpdate = source.lineDistancesNeedUpdate; + this.groupsNeedUpdate = source.groupsNeedUpdate; return this; @@ -12951,9 +12984,268 @@ } ); + // BoxGeometry + + function BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { + + Geometry.call(this); + + this.type = 'BoxGeometry'; + + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; + + this.fromBufferGeometry( new BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) ); + this.mergeVertices(); + + } + + BoxGeometry.prototype = Object.create( Geometry.prototype ); + BoxGeometry.prototype.constructor = BoxGeometry; + + // BoxBufferGeometry + + function BoxBufferGeometry( width, height, depth, widthSegments, heightSegments, depthSegments ) { + if ( width === void 0 ) width = 1; + if ( height === void 0 ) height = 1; + if ( depth === void 0 ) depth = 1; + if ( widthSegments === void 0 ) widthSegments = 1; + if ( heightSegments === void 0 ) heightSegments = 1; + if ( depthSegments === void 0 ) depthSegments = 1; + + + BufferGeometry.call(this); + + this.type = 'BoxBufferGeometry'; + + this.parameters = { + width: width, + height: height, + depth: depth, + widthSegments: widthSegments, + heightSegments: heightSegments, + depthSegments: depthSegments + }; + + var scope = this; + + // segments + + widthSegments = Math.floor( widthSegments ); + heightSegments = Math.floor( heightSegments ); + depthSegments = Math.floor( depthSegments ); + + // buffers + + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; + + // helper variables + + var numberOfVertices = 0; + var 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 ) { + + var segmentWidth = width / gridX; + var segmentHeight = height / gridY; + + var widthHalf = width / 2; + var heightHalf = height / 2; + var depthHalf = depth / 2; + + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; + + var vertexCounter = 0; + var groupCount = 0; + + var vector = new Vector3(); + + // generate vertices, normals and uvs + + for ( var iy = 0; iy < gridY1; iy ++ ) { + + var y = iy * segmentHeight - heightHalf; + + for ( var ix = 0; ix < gridX1; ix ++ ) { + + var 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 ( var iy$1 = 0; iy$1 < gridY; iy$1 ++ ) { + + for ( var ix$1 = 0; ix$1 < gridX; ix$1 ++ ) { + + var a = numberOfVertices + ix$1 + gridX1 * iy$1; + var b = numberOfVertices + ix$1 + gridX1 * ( iy$1 + 1 ); + var c = numberOfVertices + ( ix$1 + 1 ) + gridX1 * ( iy$1 + 1 ); + var d = numberOfVertices + ( ix$1 + 1 ) + gridX1 * iy$1; + + // 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; + + } + + } + + BoxBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + BoxBufferGeometry.prototype.constructor = BoxBufferGeometry; + + /** + * Uniform Utilities + */ + + function cloneUniforms( src ) { + + var dst = {}; + + for ( var u in src ) { + + dst[ u ] = {}; + + for ( var p in src[ u ] ) { + + var property = src[ u ][ p ]; + + if ( property && ( property.isColor || + property.isMatrix3 || property.isMatrix4 || + property.isVector2 || property.isVector3 || property.isVector4 || + property.isTexture ) ) { + + 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 ) { + + var merged = {}; + + for ( var u = 0; u < uniforms.length; u ++ ) { + + var tmp = cloneUniforms( uniforms[ u ] ); + + for ( var p in tmp ) { + + merged[ p ] = tmp[ p ]; + + } + + } + + return merged; + + } + + // Legacy + + var 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}"; + /** - * @author alteredq / http://alteredqualia.com/ - * * parameters = { * defines: { "label" : "value" }, * uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } }, @@ -12981,8 +13273,8 @@ this.defines = {}; this.uniforms = {}; - this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}'; - this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}'; + this.vertexShader = default_vertex; + this.fragmentShader = default_fragment; this.linewidth = 1; @@ -13041,7 +13333,7 @@ this.fragmentShader = source.fragmentShader; this.vertexShader = source.vertexShader; - this.uniforms = UniformsUtils.clone( source.uniforms ); + this.uniforms = cloneUniforms( source.uniforms ); this.defines = Object.assign( {}, source.defines ); @@ -13056,7 +13348,7 @@ this.morphTargets = source.morphTargets; this.morphNormals = source.morphNormals; - this.extensions = source.extensions; + this.extensions = Object.assign( {}, source.extensions ); return this; @@ -13073,42 +13365,49 @@ var uniform = this.uniforms[ name ]; var value = uniform.value; - if ( value.isTexture ) { + if ( value && value.isTexture ) { data.uniforms[ name ] = { type: 't', value: value.toJSON( meta ).uuid }; - } else if ( value.isColor ) { + } else if ( value && value.isColor ) { data.uniforms[ name ] = { type: 'c', value: value.getHex() }; - } else if ( value.isVector2 ) { + } else if ( value && value.isVector2 ) { data.uniforms[ name ] = { type: 'v2', value: value.toArray() }; - } else if ( value.isVector3 ) { + } else if ( value && value.isVector3 ) { data.uniforms[ name ] = { type: 'v3', value: value.toArray() }; - } else if ( value.isVector4 ) { + } else if ( value && value.isVector4 ) { data.uniforms[ name ] = { type: 'v4', value: value.toArray() }; - } else if ( value.isMatrix4 ) { + } else if ( value && value.isMatrix3 ) { + + data.uniforms[ name ] = { + type: 'm3', + value: value.toArray() + }; + + } else if ( value && value.isMatrix4 ) { data.uniforms[ name ] = { type: 'm4', @@ -13127,9802 +13426,9915 @@ } - if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; + if ( Object.keys( this.defines ).length > 0 ) { data.defines = this.defines; } data.vertexShader = this.vertexShader; data.fragmentShader = this.fragmentShader; + var extensions = {}; + + for ( var key in this.extensions ) { + + if ( this.extensions[ key ] === true ) { extensions[ key ] = true; } + + } + + if ( Object.keys( extensions ).length > 0 ) { data.extensions = extensions; } + return data; }; - /** - * @author bhouston / http://clara.io - */ - - function Ray( origin, direction ) { + function Camera() { - this.origin = ( origin !== undefined ) ? origin : new Vector3(); - this.direction = ( direction !== undefined ) ? direction : new Vector3(); + Object3D.call( this ); - } + this.type = 'Camera'; - Object.assign( Ray.prototype, { + this.matrixWorldInverse = new Matrix4(); - set: function ( origin, direction ) { + this.projectionMatrix = new Matrix4(); + this.projectionMatrixInverse = new Matrix4(); - this.origin.copy( origin ); - this.direction.copy( direction ); + } - return this; + Camera.prototype = Object.assign( Object.create( Object3D.prototype ), { - }, + constructor: Camera, - clone: function () { + isCamera: true, - return new this.constructor().copy( this ); + copy: function ( source, recursive ) { - }, + Object3D.prototype.copy.call( this, source, recursive ); - copy: function ( ray ) { + this.matrixWorldInverse.copy( source.matrixWorldInverse ); - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); + this.projectionMatrix.copy( source.projectionMatrix ); + this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); return this; }, - at: function ( t, target ) { + getWorldDirection: function ( target ) { if ( target === undefined ) { - console.warn( 'THREE.Ray: .at() target is now required' ); + console.warn( 'THREE.Camera: .getWorldDirection() target is now required' ); target = new Vector3(); } - return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + this.updateMatrixWorld( true ); + + var e = this.matrixWorld.elements; + + return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); }, - lookAt: function ( v ) { + updateMatrixWorld: function ( force ) { - this.direction.copy( v ).sub( this.origin ).normalize(); + Object3D.prototype.updateMatrixWorld.call( this, force ); - return this; + this.matrixWorldInverse.getInverse( this.matrixWorld ); }, - recast: function () { + updateWorldMatrix: function ( updateParents, updateChildren ) { - var v1 = new Vector3(); + Object3D.prototype.updateWorldMatrix.call( this, updateParents, updateChildren ); - return function recast( t ) { + this.matrixWorldInverse.getInverse( this.matrixWorld ); - this.origin.copy( this.at( t, v1 ) ); + }, - return this; + clone: function () { - }; + return new this.constructor().copy( this ); - }(), + } - closestPointToPoint: function ( point, target ) { + } ); - if ( target === undefined ) { + function PerspectiveCamera( fov, aspect, near, far ) { - console.warn( 'THREE.Ray: .closestPointToPoint() target is now required' ); - target = new Vector3(); + Camera.call( this ); - } + this.type = 'PerspectiveCamera'; - target.subVectors( point, this.origin ); + this.fov = fov !== undefined ? fov : 50; + this.zoom = 1; - var directionDistance = target.dot( this.direction ); + this.near = near !== undefined ? near : 0.1; + this.far = far !== undefined ? far : 2000; + this.focus = 10; - if ( directionDistance < 0 ) { + this.aspect = aspect !== undefined ? aspect : 1; + this.view = null; - return target.copy( this.origin ); + this.filmGauge = 35; // width of the film (default in millimeters) + this.filmOffset = 0; // horizontal film offset (same unit as gauge) - } + this.updateProjectionMatrix(); - return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + } - }, + PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), { - distanceToPoint: function ( point ) { + constructor: PerspectiveCamera, - return Math.sqrt( this.distanceSqToPoint( point ) ); + isPerspectiveCamera: true, - }, + copy: function ( source, recursive ) { - distanceSqToPoint: function () { + Camera.prototype.copy.call( this, source, recursive ); - var v1 = new Vector3(); + this.fov = source.fov; + this.zoom = source.zoom; - return function distanceSqToPoint( point ) { + this.near = source.near; + this.far = source.far; + this.focus = source.focus; - var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); + this.aspect = source.aspect; + this.view = source.view === null ? null : Object.assign( {}, source.view ); - // point behind the ray + this.filmGauge = source.filmGauge; + this.filmOffset = source.filmOffset; - if ( directionDistance < 0 ) { + return this; - return this.origin.distanceToSquared( point ); + }, - } + /** + * 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: function ( focalLength ) { - v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + // see http://www.bobatkins.com/photography/technical/field_of_view.html + var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; - return v1.distanceToSquared( point ); + this.fov = MathUtils.RAD2DEG * 2 * Math.atan( vExtentSlope ); + this.updateProjectionMatrix(); - }; + }, - }(), + /** + * Calculates the focal length from the current .fov and .filmGauge. + */ + getFocalLength: function () { - distanceSqToSegment: function () { + var vExtentSlope = Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ); - var segCenter = new Vector3(); - var segDir = new Vector3(); - var diff = new Vector3(); + return 0.5 * this.getFilmHeight() / vExtentSlope; - return function 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 + getEffectiveFOV: function () { - segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - segDir.copy( v1 ).sub( v0 ).normalize(); - diff.copy( this.origin ).sub( segCenter ); + return MathUtils.RAD2DEG * 2 * Math.atan( + Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom ); - var segExtent = v0.distanceTo( v1 ) * 0.5; - var a01 = - this.direction.dot( segDir ); - var b0 = diff.dot( this.direction ); - var b1 = - diff.dot( segDir ); - var c = diff.lengthSq(); - var det = Math.abs( 1 - a01 * a01 ); - var s0, s1, sqrDist, extDet; + }, - if ( det > 0 ) { + getFilmWidth: function () { - // The ray and segment are not parallel. + // film not completely covered in portrait format (aspect < 1) + return this.filmGauge * Math.min( this.aspect, 1 ); - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + }, - if ( s0 >= 0 ) { + getFilmHeight: function () { - if ( s1 >= - extDet ) { + // film not completely covered in landscape format (aspect > 1) + return this.filmGauge / Math.max( this.aspect, 1 ); - if ( s1 <= extDet ) { + }, - // region 0 - // Minimum at interior points of ray and segment. + /** + * 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: function ( fullWidth, fullHeight, x, y, width, height ) { - var invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + this.aspect = fullWidth / fullHeight; - } else { + if ( this.view === null ) { - // region 1 + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } - } + 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; - } else { + this.updateProjectionMatrix(); - // region 5 + }, - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + clearViewOffset: function () { - } + if ( this.view !== null ) { - } else { + this.view.enabled = false; - if ( s1 <= - extDet ) { + } - // region 4 + this.updateProjectionMatrix(); - 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 ) { + updateProjectionMatrix: function () { - // region 3 + var near = this.near, + top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom, + height = 2 * top, + width = this.aspect * height, + left = - 0.5 * width, + view = this.view; - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + if ( this.view !== null && this.view.enabled ) { - } else { + var fullWidth = view.fullWidth, + fullHeight = view.fullHeight; - // region 2 + left += view.offsetX * width / fullWidth; + top -= view.offsetY * height / fullHeight; + width *= view.width / fullWidth; + height *= view.height / fullHeight; - 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; + } - } + var skew = this.filmOffset; + if ( skew !== 0 ) { left += near * skew / this.getFilmWidth(); } - } + this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); - } else { + this.projectionMatrixInverse.getInverse( this.projectionMatrix ); - // 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; + toJSON: function ( meta ) { - } + var data = Object3D.prototype.toJSON.call( this, meta ); - if ( optionalPointOnRay ) { + data.object.fov = this.fov; + data.object.zoom = this.zoom; - optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); + data.object.near = this.near; + data.object.far = this.far; + data.object.focus = this.focus; - } + data.object.aspect = this.aspect; - if ( optionalPointOnSegment ) { + if ( this.view !== null ) { data.object.view = Object.assign( {}, this.view ); } - optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter ); + data.object.filmGauge = this.filmGauge; + data.object.filmOffset = this.filmOffset; - } + return data; - return sqrDist; + } - }; + } ); - }(), + var fov = 90, aspect = 1; - intersectSphere: function () { + function CubeCamera( near, far, renderTarget ) { - var v1 = new Vector3(); + Object3D.call( this ); - return function intersectSphere( sphere, target ) { + this.type = 'CubeCamera'; - v1.subVectors( sphere.center, this.origin ); - var tca = v1.dot( this.direction ); - var d2 = v1.dot( v1 ) - tca * tca; - var radius2 = sphere.radius * sphere.radius; + if ( renderTarget.isWebGLCubeRenderTarget !== true ) { - if ( d2 > radius2 ) return null; + console.error( 'THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.' ); + return; - var thc = Math.sqrt( radius2 - d2 ); + } - // t0 = first intersect point - entrance on front of sphere - var t0 = tca - thc; + this.renderTarget = renderTarget; - // t1 = second intersect point - exit point on back of sphere - var t1 = tca + thc; + var 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 ); - // test to see if both t0 and t1 are behind the ray - if so, return null - if ( t0 < 0 && t1 < 0 ) return null; + var 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 ); - // 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 ); + var 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 ); - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, target ); + var 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 ); - }; + var 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 ); - }(), + var 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 ); - intersectsSphere: function ( sphere ) { + this.update = function ( renderer, scene ) { - return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); + if ( this.parent === null ) { this.updateMatrixWorld(); } - }, + var currentXrEnabled = renderer.xr.enabled; + var currentRenderTarget = renderer.getRenderTarget(); - distanceToPlane: function ( plane ) { + renderer.xr.enabled = false; - var denominator = plane.normal.dot( this.direction ); + var generateMipmaps = renderTarget.texture.generateMipmaps; - if ( denominator === 0 ) { + renderTarget.texture.generateMipmaps = false; - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { + renderer.setRenderTarget( renderTarget, 0 ); + renderer.render( scene, cameraPX ); - return 0; + renderer.setRenderTarget( renderTarget, 1 ); + renderer.render( scene, cameraNX ); - } + renderer.setRenderTarget( renderTarget, 2 ); + renderer.render( scene, cameraPY ); - // Null is preferable to undefined since undefined means.... it is undefined + renderer.setRenderTarget( renderTarget, 3 ); + renderer.render( scene, cameraNY ); - return null; + renderer.setRenderTarget( renderTarget, 4 ); + renderer.render( scene, cameraPZ ); - } + renderTarget.texture.generateMipmaps = generateMipmaps; - var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + renderer.setRenderTarget( renderTarget, 5 ); + renderer.render( scene, cameraNZ ); - // Return if the ray never intersects the plane + renderer.setRenderTarget( currentRenderTarget ); - return t >= 0 ? t : null; + renderer.xr.enabled = currentXrEnabled; - }, + }; - intersectPlane: function ( plane, target ) { + this.clear = function ( renderer, color, depth, stencil ) { - var t = this.distanceToPlane( plane ); + var currentRenderTarget = renderer.getRenderTarget(); - if ( t === null ) { + for ( var i = 0; i < 6; i ++ ) { - return null; + renderer.setRenderTarget( renderTarget, i ); - } + renderer.clear( color, depth, stencil ); - return this.at( t, target ); + } - }, + renderer.setRenderTarget( currentRenderTarget ); - intersectsPlane: function ( plane ) { + }; - // check if the ray lies on the plane first + } - var distToPoint = plane.distanceToPoint( this.origin ); + CubeCamera.prototype = Object.create( Object3D.prototype ); + CubeCamera.prototype.constructor = CubeCamera; - if ( distToPoint === 0 ) { + function WebGLCubeRenderTarget( size, options, dummy ) { - return true; + if ( Number.isInteger( options ) ) { - } + console.warn( 'THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )' ); - var denominator = plane.normal.dot( this.direction ); + options = dummy; - if ( denominator * distToPoint < 0 ) { + } - return true; + WebGLRenderTarget.call( this, size, size, options ); - } + } - // ray origin is behind the plane (and is pointing behind it) + WebGLCubeRenderTarget.prototype = Object.create( WebGLRenderTarget.prototype ); + WebGLCubeRenderTarget.prototype.constructor = WebGLCubeRenderTarget; - return false; + WebGLCubeRenderTarget.prototype.isWebGLCubeRenderTarget = true; - }, + WebGLCubeRenderTarget.prototype.fromEquirectangularTexture = function ( renderer, texture ) { - intersectBox: function ( box, target ) { + this.texture.type = texture.type; + this.texture.format = RGBAFormat; // see #18859 + this.texture.encoding = texture.encoding; - var tmin, tmax, tymin, tymax, tzmin, tzmax; + this.texture.generateMipmaps = texture.generateMipmaps; + this.texture.minFilter = texture.minFilter; + this.texture.magFilter = texture.magFilter; - var invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; + var scene = new Scene(); - var origin = this.origin; + var shader = { - if ( invdirx >= 0 ) { + uniforms: { + tEquirect: { value: null }, + }, - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; + vertexShader: /* glsl */"\n\n\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t}\n\n\t\t\tvoid main() {\n\n\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t#include \n\t\t\t\t#include \n\n\t\t\t}\n\t\t", - } else { + fragmentShader: /* glsl */"\n\n\t\t\tuniform sampler2D tEquirect;\n\n\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t#include \n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t}\n\t\t" + }; - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; + var material = new ShaderMaterial( { - } + name: 'CubemapFromEquirect', - if ( invdiry >= 0 ) { + uniforms: cloneUniforms( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + side: BackSide, + blending: NoBlending - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; + } ); - } else { + material.uniforms.tEquirect.value = texture; - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; + var mesh = new Mesh( new BoxBufferGeometry( 5, 5, 5 ), material ); - } + scene.add( mesh ); - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; + var camera = new CubeCamera( 1, 10, this ); + camera.update( renderer, scene ); - // These lines also handle the case where tmin or tmax is NaN - // (result of 0 * Infinity). x !== x returns true if x is NaN + mesh.geometry.dispose(); + mesh.material.dispose(); - if ( tymin > tmin || tmin !== tmin ) tmin = tymin; + return this; - if ( tymax < tmax || tmax !== tmax ) tmax = tymax; + }; - if ( invdirz >= 0 ) { + function DataTexture( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - } else { + this.image = { data: data || null, width: width || 1, height: height || 1 }; - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - } + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; + this.needsUpdate = true; - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; + } - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; + DataTexture.prototype = Object.create( Texture.prototype ); + DataTexture.prototype.constructor = DataTexture; - //return point closest to the ray (positive side) + DataTexture.prototype.isDataTexture = true; - if ( tmax < 0 ) return null; + var _sphere$1 = new Sphere(); + var _vector$5 = new Vector3(); - return this.at( tmin >= 0 ? tmin : tmax, target ); + function Frustum( p0, p1, p2, p3, p4, p5 ) { - }, + this.planes = [ - intersectsBox: ( function () { + ( p0 !== undefined ) ? p0 : new Plane(), + ( p1 !== undefined ) ? p1 : new Plane(), + ( p2 !== undefined ) ? p2 : new Plane(), + ( p3 !== undefined ) ? p3 : new Plane(), + ( p4 !== undefined ) ? p4 : new Plane(), + ( p5 !== undefined ) ? p5 : new Plane() - var v = new Vector3(); + ]; - return function intersectsBox( box ) { + } - return this.intersectBox( box, v ) !== null; + Object.assign( Frustum.prototype, { - }; + set: function ( p0, p1, p2, p3, p4, p5 ) { - } )(), + var planes = this.planes; - intersectTriangle: function () { + planes[ 0 ].copy( p0 ); + planes[ 1 ].copy( p1 ); + planes[ 2 ].copy( p2 ); + planes[ 3 ].copy( p3 ); + planes[ 4 ].copy( p4 ); + planes[ 5 ].copy( p5 ); - // Compute the offset origin, edges, and normal. - var diff = new Vector3(); - var edge1 = new Vector3(); - var edge2 = new Vector3(); - var normal = new Vector3(); + return this; - return function intersectTriangle( a, b, c, backfaceCulling, target ) { + }, - // from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h + clone: function () { - edge1.subVectors( b, a ); - edge2.subVectors( c, a ); - normal.crossVectors( edge1, edge2 ); + return new this.constructor().copy( this ); - // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, - // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by - // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) - // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) - // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) - var DdN = this.direction.dot( normal ); - var sign; + }, - if ( DdN > 0 ) { + copy: function ( frustum ) { - if ( backfaceCulling ) return null; - sign = 1; + var planes = this.planes; - } else if ( DdN < 0 ) { + for ( var i = 0; i < 6; i ++ ) { - sign = - 1; - DdN = - DdN; + planes[ i ].copy( frustum.planes[ i ] ); - } else { + } - return null; + return this; - } + }, - diff.subVectors( this.origin, a ); - var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); + setFromProjectionMatrix: function ( m ) { - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { + var planes = this.planes; + var me = m.elements; + var me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; + var me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; + var me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; + var me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; - return null; + 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; - var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); + }, - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { + intersectsObject: function ( object ) { - return null; + var geometry = object.geometry; - } + if ( geometry.boundingSphere === null ) { geometry.computeBoundingSphere(); } - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { + _sphere$1.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); - return null; + return this.intersectsSphere( _sphere$1 ); - } + }, - // Line intersects triangle, check if ray does. - var QdN = - sign * diff.dot( normal ); + intersectsSprite: function ( sprite ) { - // t < 0, no intersection - if ( QdN < 0 ) { + _sphere$1.center.set( 0, 0, 0 ); + _sphere$1.radius = 0.7071067811865476; + _sphere$1.applyMatrix4( sprite.matrixWorld ); - return null; + return this.intersectsSphere( _sphere$1 ); - } + }, - // Ray intersects triangle. - return this.at( QdN / DdN, target ); + intersectsSphere: function ( sphere ) { - }; + var planes = this.planes; + var center = sphere.center; + var negRadius = - sphere.radius; - }(), + for ( var i = 0; i < 6; i ++ ) { - applyMatrix4: function ( matrix4 ) { + var distance = planes[ i ].distanceToPoint( center ); - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); + if ( distance < negRadius ) { - return this; + return false; - }, + } - equals: function ( ray ) { + } - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + return true; - } + }, - } ); + intersectsBox: function ( box ) { - /** - * @author bhouston / http://clara.io - * @author mrdoob / http://mrdoob.com/ - */ + var planes = this.planes; - function Triangle( a, b, c ) { + for ( var i = 0; i < 6; i ++ ) { - this.a = ( a !== undefined ) ? a : new Vector3(); - this.b = ( b !== undefined ) ? b : new Vector3(); - this.c = ( c !== undefined ) ? c : new Vector3(); + var plane = planes[ i ]; - } + // corner at max distance - Object.assign( Triangle, { + _vector$5.x = plane.normal.x > 0 ? box.max.x : box.min.x; + _vector$5.y = plane.normal.y > 0 ? box.max.y : box.min.y; + _vector$5.z = plane.normal.z > 0 ? box.max.z : box.min.z; - getNormal: function () { + if ( plane.distanceToPoint( _vector$5 ) < 0 ) { - var v0 = new Vector3(); + return false; - return function getNormal( a, b, c, target ) { + } - if ( target === undefined ) { + } - console.warn( 'THREE.Triangle: .getNormal() target is now required' ); - target = new Vector3(); + return true; - } + }, - target.subVectors( c, b ); - v0.subVectors( a, b ); - target.cross( v0 ); + containsPoint: function ( point ) { - var targetLengthSq = target.lengthSq(); - if ( targetLengthSq > 0 ) { + var planes = this.planes; - return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); + for ( var i = 0; i < 6; i ++ ) { - } + if ( planes[ i ].distanceToPoint( point ) < 0 ) { - return target.set( 0, 0, 0 ); + return false; - }; + } - }(), + } - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - getBarycoord: function () { + return true; - var v0 = new Vector3(); - var v1 = new Vector3(); - var v2 = new Vector3(); + } - return function getBarycoord( point, a, b, c, target ) { + } ); - v0.subVectors( c, a ); - v1.subVectors( b, a ); - v2.subVectors( point, a ); + /** + * Uniforms library for shared webgl shaders + */ - var dot00 = v0.dot( v0 ); - var dot01 = v0.dot( v1 ); - var dot02 = v0.dot( v2 ); - var dot11 = v1.dot( v1 ); - var dot12 = v1.dot( v2 ); + var UniformsLib = { - var denom = ( dot00 * dot11 - dot01 * dot01 ); + common: { - if ( target === undefined ) { + diffuse: { value: new Color( 0xeeeeee ) }, + opacity: { value: 1.0 }, - console.warn( 'THREE.Triangle: .getBarycoord() target is now required' ); - target = new Vector3(); + map: { value: null }, + uvTransform: { value: new Matrix3() }, + uv2Transform: { value: new Matrix3() }, - } + alphaMap: { value: null }, - // 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 ); + specularmap: { - } + specularMap: { value: null }, - var invDenom = 1 / denom; - var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + }, - // barycentric coordinates must always sum to 1 - return target.set( 1 - u - v, v, u ); + envmap: { - }; + envMap: { value: null }, + flipEnvMap: { value: - 1 }, + reflectivity: { value: 1.0 }, + refractionRatio: { value: 0.98 }, + maxMipLevel: { value: 0 } - }(), + }, - containsPoint: function () { + aomap: { - var v1 = new Vector3(); + aoMap: { value: null }, + aoMapIntensity: { value: 1 } - return function containsPoint( point, a, b, c ) { + }, - Triangle.getBarycoord( point, a, b, c, v1 ); + lightmap: { - return ( v1.x >= 0 ) && ( v1.y >= 0 ) && ( ( v1.x + v1.y ) <= 1 ); + lightMap: { value: null }, + lightMapIntensity: { value: 1 } - }; + }, - }(), + emissivemap: { - getUV: function () { + emissiveMap: { value: null } - var barycoord = new Vector3(); + }, - return function getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { + bumpmap: { - this.getBarycoord( point, p1, p2, p3, barycoord ); + bumpMap: { value: null }, + bumpScale: { value: 1 } - target.set( 0, 0 ); - target.addScaledVector( uv1, barycoord.x ); - target.addScaledVector( uv2, barycoord.y ); - target.addScaledVector( uv3, barycoord.z ); + }, - return target; + normalmap: { - }; + normalMap: { value: null }, + normalScale: { value: new Vector2( 1, 1 ) } - }() + }, - } ); + displacementmap: { - Object.assign( Triangle.prototype, { + displacementMap: { value: null }, + displacementScale: { value: 1 }, + displacementBias: { value: 0 } - set: function ( a, b, c ) { + }, - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); + roughnessmap: { - return this; + roughnessMap: { value: null } }, - setFromPointsAndIndices: function ( points, i0, i1, i2 ) { - - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); + metalnessmap: { - return this; + metalnessMap: { value: null } }, - clone: function () { + gradientmap: { - return new this.constructor().copy( this ); + gradientMap: { value: null } }, - copy: function ( triangle ) { - - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); + fog: { - return this; + fogDensity: { value: 0.00025 }, + fogNear: { value: 1 }, + fogFar: { value: 2000 }, + fogColor: { value: new Color( 0xffffff ) } }, - getArea: function () { + lights: { - var v0 = new Vector3(); - var v1 = new Vector3(); + ambientLightColor: { value: [] }, - return function getArea() { + lightProbe: { value: [] }, - v0.subVectors( this.c, this.b ); - v1.subVectors( this.a, this.b ); + directionalLights: { value: [], properties: { + direction: {}, + color: {} + } }, - return v0.cross( v1 ).length() * 0.5; + directionalLightShadows: { value: [], properties: { + shadowBias: {}, + shadowNormalBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, - }; + directionalShadowMap: { value: [] }, + directionalShadowMatrix: { value: [] }, - }(), + spotLights: { value: [], properties: { + color: {}, + position: {}, + direction: {}, + distance: {}, + coneCos: {}, + penumbraCos: {}, + decay: {} + } }, - getMidpoint: function ( target ) { + spotLightShadows: { value: [], properties: { + shadowBias: {}, + shadowNormalBias: {}, + shadowRadius: {}, + shadowMapSize: {} + } }, - if ( target === undefined ) { + spotShadowMap: { value: [] }, + spotShadowMatrix: { value: [] }, - console.warn( 'THREE.Triangle: .getMidpoint() target is now required' ); - target = new Vector3(); + pointLights: { value: [], properties: { + color: {}, + position: {}, + decay: {}, + distance: {} + } }, - } + pointLightShadows: { value: [], properties: { + shadowBias: {}, + shadowNormalBias: {}, + shadowRadius: {}, + shadowMapSize: {}, + shadowCameraNear: {}, + shadowCameraFar: {} + } }, - return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + 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: {} + } } }, - getNormal: function ( target ) { + points: { - return Triangle.getNormal( this.a, this.b, this.c, target ); + diffuse: { value: new Color( 0xeeeeee ) }, + opacity: { value: 1.0 }, + size: { value: 1.0 }, + scale: { value: 1.0 }, + map: { value: null }, + alphaMap: { value: null }, + uvTransform: { value: new Matrix3() } }, - getPlane: function ( target ) { + sprite: { - if ( target === undefined ) { + diffuse: { value: new Color( 0xeeeeee ) }, + opacity: { value: 1.0 }, + center: { value: new Vector2( 0.5, 0.5 ) }, + rotation: { value: 0.0 }, + map: { value: null }, + alphaMap: { value: null }, + uvTransform: { value: new Matrix3() } - console.warn( 'THREE.Triangle: .getPlane() target is now required' ); - target = new Vector3(); + } - } + }; - return target.setFromCoplanarPoints( this.a, this.b, this.c ); + function WebGLAnimation() { - }, + var context = null; + var isAnimating = false; + var animationLoop = null; + var requestId = null; - getBarycoord: function ( point, target ) { + function onAnimationFrame( time, frame ) { - return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); + animationLoop( time, frame ); - }, + requestId = context.requestAnimationFrame( onAnimationFrame ); - containsPoint: function ( point ) { + } - return Triangle.containsPoint( point, this.a, this.b, this.c ); + return { - }, + start: function () { - getUV: function ( point, uv1, uv2, uv3, result ) { + if ( isAnimating === true ) { return; } + if ( animationLoop === null ) { return; } - return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, result ); + requestId = context.requestAnimationFrame( onAnimationFrame ); - }, + isAnimating = true; - intersectsBox: function ( box ) { + }, - return box.intersectsTriangle( this ); + stop: function () { - }, + context.cancelAnimationFrame( requestId ); - closestPointToPoint: function () { + isAnimating = false; - var vab = new Vector3(); - var vac = new Vector3(); - var vbc = new Vector3(); - var vap = new Vector3(); - var vbp = new Vector3(); - var vcp = new Vector3(); + }, - return function closestPointToPoint( p, target ) { + setAnimationLoop: function ( callback ) { - if ( target === undefined ) { + animationLoop = callback; - console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' ); - target = new Vector3(); + }, - } + setContext: function ( value ) { - var a = this.a, b = this.b, c = this.c; - var v, w; + context = value; - // 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 ); - var d1 = vab.dot( vap ); - var d2 = vac.dot( vap ); - if ( d1 <= 0 && d2 <= 0 ) { + }; - // vertex region of A; barycentric coords (1, 0, 0) - return target.copy( a ); + } - } + function WebGLAttributes( gl, capabilities ) { - vbp.subVectors( p, b ); - var d3 = vab.dot( vbp ); - var d4 = vac.dot( vbp ); - if ( d3 >= 0 && d4 <= d3 ) { + var isWebGL2 = capabilities.isWebGL2; - // vertex region of B; barycentric coords (0, 1, 0) - return target.copy( b ); + var buffers = new WeakMap(); - } + function createBuffer( attribute, bufferType ) { - var vc = d1 * d4 - d3 * d2; - if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { + var array = attribute.array; + var usage = attribute.usage; - v = d1 / ( d1 - d3 ); - // edge region of AB; barycentric coords (1-v, v, 0) - return target.copy( a ).addScaledVector( vab, v ); + var buffer = gl.createBuffer(); - } + gl.bindBuffer( bufferType, buffer ); + gl.bufferData( bufferType, array, usage ); - vcp.subVectors( p, c ); - var d5 = vab.dot( vcp ); - var d6 = vac.dot( vcp ); - if ( d6 >= 0 && d5 <= d6 ) { + attribute.onUploadCallback(); - // vertex region of C; barycentric coords (0, 0, 1) - return target.copy( c ); + var type = 5126; - } + if ( array instanceof Float32Array ) { - var vb = d5 * d2 - d1 * d6; - if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { + type = 5126; - w = d2 / ( d2 - d6 ); - // edge region of AC; barycentric coords (1-w, 0, w) - return target.copy( a ).addScaledVector( vac, w ); + } else if ( array instanceof Float64Array ) { - } + console.warn( 'THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.' ); - var va = d3 * d6 - d5 * d4; - if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { + } else if ( array instanceof Uint16Array ) { - 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 + type = 5123; - } + } else if ( array instanceof Int16Array ) { - // face region - var denom = 1 / ( va + vb + vc ); - // u = va * denom - v = vb * denom; - w = vc * denom; - return target.copy( a ).addScaledVector( vab, v ).addScaledVector( vac, w ); + type = 5122; - }; + } else if ( array instanceof Uint32Array ) { - }(), + type = 5125; - equals: function ( triangle ) { + } else if ( array instanceof Int32Array ) { - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + type = 5124; - } + } else if ( array instanceof Int8Array ) { - } ); + type = 5120; - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * 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: , - * - * skinning: , - * morphTargets: - * } - */ + } else if ( array instanceof Uint8Array ) { - function MeshBasicMaterial( parameters ) { + type = 5121; - Material.call( this ); + } - this.type = 'MeshBasicMaterial'; + return { + buffer: buffer, + type: type, + bytesPerElement: array.BYTES_PER_ELEMENT, + version: attribute.version + }; - this.color = new Color( 0xffffff ); // emissive + } - this.map = null; + function updateBuffer( buffer, attribute, bufferType ) { - this.lightMap = null; - this.lightMapIntensity = 1.0; + var array = attribute.array; + var updateRange = attribute.updateRange; - this.aoMap = null; - this.aoMapIntensity = 1.0; + gl.bindBuffer( bufferType, buffer ); - this.specularMap = null; + if ( updateRange.count === - 1 ) { - this.alphaMap = null; + // Not using update ranges - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + gl.bufferSubData( bufferType, 0, array ); - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + } else { - this.skinning = false; - this.morphTargets = false; + if ( isWebGL2 ) { - this.lights = false; + gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, + array, updateRange.offset, updateRange.count ); - this.setValues( parameters ); + } else { - } + gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, + array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); - MeshBasicMaterial.prototype = Object.create( Material.prototype ); - MeshBasicMaterial.prototype.constructor = MeshBasicMaterial; + } - MeshBasicMaterial.prototype.isMeshBasicMaterial = true; + updateRange.count = - 1; // reset range - MeshBasicMaterial.prototype.copy = function ( source ) { + } - Material.prototype.copy.call( this, 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; + function get( attribute ) { - this.specularMap = source.specularMap; + if ( attribute.isInterleavedBufferAttribute ) { attribute = attribute.data; } - this.alphaMap = source.alphaMap; + return buffers.get( attribute ); - 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; + function remove( attribute ) { - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; + if ( attribute.isInterleavedBufferAttribute ) { attribute = attribute.data; } - return this; + var data = buffers.get( attribute ); - }; + if ( data ) { - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author mikael emtinger / http://gomo.se/ - * @author jonobr1 / http://jonobr1.com/ - */ + gl.deleteBuffer( data.buffer ); - function Mesh( geometry, material ) { + buffers.delete( attribute ); - Object3D.call( this ); + } - this.type = 'Mesh'; + } - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new MeshBasicMaterial( { color: Math.random() * 0xffffff } ); + function update( attribute, bufferType ) { - this.drawMode = TrianglesDrawMode; + if ( attribute.isInterleavedBufferAttribute ) { attribute = attribute.data; } - this.updateMorphTargets(); + var data = buffers.get( attribute ); - } + if ( data === undefined ) { - Mesh.prototype = Object.assign( Object.create( Object3D.prototype ), { + buffers.set( attribute, createBuffer( attribute, bufferType ) ); - constructor: Mesh, + } else if ( data.version < attribute.version ) { - isMesh: true, + updateBuffer( data.buffer, attribute, bufferType ); - setDrawMode: function ( value ) { + data.version = attribute.version; - this.drawMode = value; + } - }, + } - copy: function ( source ) { + return { - Object3D.prototype.copy.call( this, source ); + get: get, + remove: remove, + update: update - this.drawMode = source.drawMode; + }; - if ( source.morphTargetInfluences !== undefined ) { + } - this.morphTargetInfluences = source.morphTargetInfluences.slice(); + // PlaneGeometry - } + function PlaneGeometry( width, height, widthSegments, heightSegments ) { - if ( source.morphTargetDictionary !== undefined ) { + Geometry.call( this ); - this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); + this.type = 'PlaneGeometry'; - } + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - return this; + this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) ); + this.mergeVertices(); - }, + } - updateMorphTargets: function () { + PlaneGeometry.prototype = Object.create( Geometry.prototype ); + PlaneGeometry.prototype.constructor = PlaneGeometry; - var geometry = this.geometry; - var m, ml, name; + // PlaneBufferGeometry - if ( geometry.isBufferGeometry ) { + function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) { - var morphAttributes = geometry.morphAttributes; - var keys = Object.keys( morphAttributes ); + BufferGeometry.call( this ); - if ( keys.length > 0 ) { + this.type = 'PlaneBufferGeometry'; - var morphAttribute = morphAttributes[ keys[ 0 ] ]; + this.parameters = { + width: width, + height: height, + widthSegments: widthSegments, + heightSegments: heightSegments + }; - if ( morphAttribute !== undefined ) { + width = width || 1; + height = height || 1; - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + var width_half = width / 2; + var height_half = height / 2; - for ( m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + var gridX = Math.floor( widthSegments ) || 1; + var gridY = Math.floor( heightSegments ) || 1; - name = morphAttribute[ m ].name || String( m ); + var gridX1 = gridX + 1; + var gridY1 = gridY + 1; - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; + var segment_width = width / gridX; + var segment_height = height / gridY; - } + // buffers - } + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - } + // generate vertices, normals and uvs - } else { + for ( var iy = 0; iy < gridY1; iy ++ ) { - var morphTargets = geometry.morphTargets; + var y = iy * segment_height - height_half; - if ( morphTargets !== undefined && morphTargets.length > 0 ) { + for ( var ix = 0; ix < gridX1; ix ++ ) { - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + var x = ix * segment_width - width_half; - for ( m = 0, ml = morphTargets.length; m < ml; m ++ ) { + vertices.push( x, - y, 0 ); - name = morphTargets[ m ].name || String( m ); + normals.push( 0, 0, 1 ); - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; + uvs.push( ix / gridX ); + uvs.push( 1 - ( iy / gridY ) ); - } + } - } + } - } + // indices - }, + for ( var iy$1 = 0; iy$1 < gridY; iy$1 ++ ) { - raycast: ( function () { + for ( var ix$1 = 0; ix$1 < gridX; ix$1 ++ ) { - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); + var a = ix$1 + gridX1 * iy$1; + var b = ix$1 + gridX1 * ( iy$1 + 1 ); + var c = ( ix$1 + 1 ) + gridX1 * ( iy$1 + 1 ); + var d = ( ix$1 + 1 ) + gridX1 * iy$1; - var vA = new Vector3(); - var vB = new Vector3(); - var vC = new Vector3(); + // faces - var tempA = new Vector3(); - var tempB = new Vector3(); - var tempC = new Vector3(); + indices.push( a, b, d ); + indices.push( b, c, d ); - var uvA = new Vector2(); - var uvB = new Vector2(); - var uvC = new Vector2(); + } - var intersectionPoint = new Vector3(); - var intersectionPointWorld = new Vector3(); + } - function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { + // build geometry - var intersect; + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - if ( material.side === BackSide ) { + } - intersect = ray.intersectTriangle( pC, pB, pA, true, point ); + PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry; - } else { + var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif"; - intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); + var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - } + var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif"; - if ( intersect === null ) return null; + 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.specularRoughness );\n\t#endif\n#endif"; - intersectionPointWorld.copy( point ); - intersectionPointWorld.applyMatrix4( object.matrixWorld ); + var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - var distance = raycaster.ray.origin.distanceTo( intersectionPointWorld ); + var begin_vertex = "vec3 transformed = vec3( position );"; - if ( distance < raycaster.near || distance > raycaster.far ) return null; + var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; - return { - distance: distance, - point: intersectionPointWorld.clone(), - object: object - }; + var bsdfs = "vec2 integrateSpecularBRDF( const in float dotNV, const in float roughness ) {\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\treturn vec2( -1.04, 1.04 ) * a004 + r.zw;\n}\nfloat punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, 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 dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat 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}\nvec3 BRDF_Specular_GGX_Environment( const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.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}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}\n#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);\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_Specular_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 ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\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"; - function checkBufferGeometryIntersection( object, material, raycaster, ray, position, uv, a, b, c ) { + 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"; - vA.fromBufferAttribute( position, a ); - vB.fromBufferAttribute( position, b ); - vC.fromBufferAttribute( position, c ); + var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; - var intersection = checkIntersection( object, material, raycaster, ray, vA, vB, vC, intersectionPoint ); + var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; - if ( intersection ) { + var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; - if ( uv ) { + var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif"; - uvA.fromBufferAttribute( uv, a ); - uvB.fromBufferAttribute( uv, b ); - uvC.fromBufferAttribute( uv, c ); + var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif"; - intersection.uv = Triangle.getUV( intersectionPoint, vA, vB, vC, uvA, uvB, uvC, new Vector2() ); + var color_pars_vertex = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif"; - } + var color_vertex = "#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif"; - var face = new Face3( a, b, c ); - Triangle.getNormal( vA, vB, vC, face.normal ); + 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 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 max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\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 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}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 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}"; - intersection.face = face; + var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_maxMipLevel 8.0\n#define cubeUV_minMipLevel 4.0\n#define cubeUV_maxTileSize 256.0\n#define cubeUV_minTileSize 16.0\nfloat getFace(vec3 direction) {\n vec3 absDirection = abs(direction);\n float face = -1.0;\n if (absDirection.x > absDirection.z) {\n if (absDirection.x > absDirection.y)\n face = direction.x > 0.0 ? 0.0 : 3.0;\n else\n face = direction.y > 0.0 ? 1.0 : 4.0;\n } else {\n if (absDirection.z > absDirection.y)\n face = direction.z > 0.0 ? 2.0 : 5.0;\n else\n face = direction.y > 0.0 ? 1.0 : 4.0;\n }\n return face;\n}\nvec2 getUV(vec3 direction, float face) {\n vec2 uv;\n if (face == 0.0) {\n uv = vec2(direction.z, direction.y) / abs(direction.x); } else if (face == 1.0) {\n uv = vec2(-direction.x, -direction.z) / abs(direction.y); } else if (face == 2.0) {\n uv = vec2(-direction.x, direction.y) / abs(direction.z); } else if (face == 3.0) {\n uv = vec2(-direction.z, direction.y) / abs(direction.x); } else if (face == 4.0) {\n uv = vec2(-direction.x, direction.z) / abs(direction.y); } else {\n uv = vec2(direction.x, direction.y) / abs(direction.z); }\n return 0.5 * (uv + 1.0);\n}\nvec3 bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {\n float face = getFace(direction);\n float filterInt = max(cubeUV_minMipLevel - mipInt, 0.0);\n mipInt = max(mipInt, cubeUV_minMipLevel);\n float faceSize = exp2(mipInt);\n float texelSize = 1.0 / (3.0 * cubeUV_maxTileSize);\n vec2 uv = getUV(direction, face) * (faceSize - 1.0);\n vec2 f = fract(uv);\n uv += 0.5 - f;\n if (face > 2.0) {\n uv.y += faceSize;\n face -= 3.0;\n }\n uv.x += face * faceSize;\n if(mipInt < cubeUV_maxMipLevel){\n uv.y += 2.0 * cubeUV_maxTileSize;\n }\n uv.y += filterInt * 2.0 * cubeUV_minTileSize;\n uv.x += 3.0 * max(0.0, cubeUV_maxTileSize - 2.0 * faceSize);\n uv *= texelSize;\n vec3 tl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.x += texelSize;\n vec3 tr = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.y += texelSize;\n vec3 br = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n uv.x -= texelSize;\n vec3 bl = envMapTexelToLinear(texture2D(envMap, uv)).rgb;\n vec3 tm = mix(tl, tr, f.x);\n vec3 bm = mix(bl, br, f.x);\n return mix(tm, bm, f.y);\n}\n#define r0 1.0\n#define v0 0.339\n#define m0 -2.0\n#define r1 0.8\n#define v1 0.276\n#define m1 -1.0\n#define r4 0.4\n#define v4 0.046\n#define m4 2.0\n#define r5 0.305\n#define v5 0.016\n#define m5 3.0\n#define r6 0.21\n#define v6 0.0038\n#define m6 4.0\nfloat roughnessToMip(float roughness) {\n float mip = 0.0;\n if (roughness >= r1) {\n mip = (r0 - roughness) * (m1 - m0) / (r0 - r1) + m0;\n } else if (roughness >= r4) {\n mip = (r1 - roughness) * (m4 - m1) / (r1 - r4) + m1;\n } else if (roughness >= r5) {\n mip = (r4 - roughness) * (m5 - m4) / (r4 - r5) + m4;\n } else if (roughness >= r6) {\n mip = (r5 - roughness) * (m6 - m5) / (r5 - r6) + m5;\n } else {\n mip = -2.0 * log2(1.16 * roughness); }\n return mip;\n}\nvec4 textureCubeUV(sampler2D envMap, vec3 sampleDir, float roughness) {\n float mip = clamp(roughnessToMip(roughness), m0, cubeUV_maxMipLevel);\n float mipF = fract(mip);\n float mipInt = floor(mip);\n vec3 color0 = bilinearCubeUV(envMap, sampleDir, mipInt);\n if (mipF == 0.0) {\n return vec4(color0, 1.0);\n } else {\n vec3 color1 = bilinearCubeUV(envMap, sampleDir, mipInt + 1.0);\n return vec4(mix(color0, color1, mipF), 1.0);\n }\n}\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"; - return intersection; + 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"; - return function raycast( raycaster, intersects ) { + 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 geometry = this.geometry; - var material = this.material; - var matrixWorld = this.matrixWorld; + var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; - if ( material === undefined ) return; + var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; - // Checking boundingSphere distance to ray + 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}"; - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\t\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#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec2 sampleUV = equirectUv( reflectVec );\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\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"; - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); + 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"; - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + 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"; - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + 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"; - // Check boundingBox before continuing + var fog_vertex = "#ifdef USE_FOG\n\tfogDepth = - mvPosition.z;\n#endif"; - if ( geometry.boundingBox !== null ) { + var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif"; - if ( ray.intersectsBox( geometry.boundingBox ) === false ) return; + var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"; - } + var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif"; - var intersection; + 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}"; - if ( geometry.isBufferGeometry ) { + var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif"; - var a, b, c; - var index = geometry.index; - var position = geometry.attributes.position; - var uv = geometry.attributes.uv; - var groups = geometry.groups; - var drawRange = geometry.drawRange; - var i, j, il, jl; - var group, groupMaterial; - var start, end; + var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; - if ( index !== null ) { + 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\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\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\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\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\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\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"; - // indexed buffer geometry + 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\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D 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\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif"; - if ( Array.isArray( material ) ) { + 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 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t vec3 reflectVec = reflect( -viewDir, normal );\n\t\t reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t vec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV = equirectUv( reflectVec );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif"; - for ( i = 0, il = groups.length; i < il; i ++ ) { + var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; - group = groups[ i ]; - groupMaterial = material[ group.materialIndex ]; + var lights_toon_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\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\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_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_Diffuse_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)"; - start = Math.max( group.start, drawRange.start ); - end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); + var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; - for ( j = start, jl = end; j < jl; j += 3 ) { + var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\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\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)"; - a = index.getX( j ); - b = index.getX( j + 1 ); - c = index.getX( j + 2 ); + 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.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 1.0 );\n#ifdef REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\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.sheenColor = sheen;\n#endif"; - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, ray, position, uv, a, b, c ); + var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat specularRoughness;\n\tvec3 specularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearcoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 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.specularRoughness;\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#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_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_Diffuse_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 CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * 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}"; - if ( intersection ) { + var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef 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\tgetPointDirectLightIrradiance( 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\tgetSpotDirectLightIrradiance( 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\tgetDirectionalDirectLightIrradiance( 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"; - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics - intersects.push( intersection ); + 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 += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, maxMipLevel );\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"; - } else { + 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"; - start = Math.max( 0, drawRange.start ); - end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); + 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"; - for ( i = start, il = end; i < il; i += 3 ) { + var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif"; - a = index.getX( i ); - b = index.getX( i + 1 ); - c = index.getX( i + 2 ); + var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; - intersection = checkBufferGeometryIntersection( this, material, raycaster, ray, position, uv, a, b, c ); + 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"; - if ( intersection ) { + 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"; - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics - intersects.push( intersection ); + 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"; - } else if ( position !== undefined ) { + 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"; - // non-indexed buffer geometry + var normal_fragment_begin = "#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 * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\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 * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\tbitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\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;"; - if ( Array.isArray( material ) ) { + 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 * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\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 );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif"; - for ( i = 0, il = groups.length; i < il; i ++ ) { + 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 ) {\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\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif"; - group = groups[ i ]; - groupMaterial = material[ group.materialIndex ]; + var clearcoat_normal_fragment_begin = "#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif"; - start = Math.max( group.start, drawRange.start ); - end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); + 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 );\n\t#endif\n#endif"; - for ( j = start, jl = end; j < jl; j += 3 ) { + 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"; - a = j; - b = j + 1; - c = j + 2; + 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}"; - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, ray, position, uv, a, b, c ); + var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; - if ( intersection ) { + 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;"; - intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics - intersects.push( intersection ); + 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"; - } else { + 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"; - start = Math.max( 0, drawRange.start ); - end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); + 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"; - for ( i = start, il = end; i < il; i += 3 ) { + 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"; - a = i; - b = i + 1; - c = i + 2; + 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}"; - intersection = checkBufferGeometryIntersection( this, material, raycaster, ray, position, uv, a, b, c ); + 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"; - if ( intersection ) { + 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"; - intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics - intersects.push( intersection ); + 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"; - } else if ( geometry.isGeometry ) { + 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 fvA, fvB, fvC; - var isMultiMaterial = Array.isArray( material ); + var transmissionmap_fragment = "#ifdef USE_TRANSMISSIONMAP\n\ttotalTransmission *= texture2D( transmissionMap, vUv ).r;\n#endif"; - var vertices = geometry.vertices; - var faces = geometry.faces; - var uvs; + var transmissionmap_pars_fragment = "#ifdef USE_TRANSMISSIONMAP\n\tuniform sampler2D transmissionMap;\n#endif"; - var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; - if ( faceVertexUvs.length > 0 ) uvs = faceVertexUvs; + var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif"; - for ( var f = 0, fl = faces.length; f < fl; f ++ ) { + 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 face = faces[ f ]; - var faceMaterial = isMultiMaterial ? material[ face.materialIndex ] : material; + var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif"; - if ( faceMaterial === undefined ) continue; + var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; - fvA = vertices[ face.a ]; - fvB = vertices[ face.b ]; - fvC = vertices[ face.c ]; + 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"; - if ( faceMaterial.morphTargets === true ) { + var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif"; - var morphTargets = geometry.morphTargets; - var morphInfluences = this.morphTargetInfluences; + var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\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"; - vA.set( 0, 0, 0 ); - vB.set( 0, 0, 0 ); - vC.set( 0, 0, 0 ); + 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}"; - for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { + 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 influence = morphInfluences[ t ]; + 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}"; - if ( influence === 0 ) continue; + 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 targets = morphTargets[ t ].vertices; + 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 \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}"; - vA.addScaledVector( tempA.subVectors( targets[ face.a ], fvA ), influence ); - vB.addScaledVector( tempB.subVectors( targets[ face.b ], fvB ), influence ); - vC.addScaledVector( tempC.subVectors( targets[ face.c ], fvC ), influence ); + 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 \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}"; - vA.add( fvA ); - vB.add( fvB ); - vC.add( fvC ); + 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}"; - fvA = vA; - fvB = vB; - fvC = vC; + 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}"; - intersection = checkIntersection( this, faceMaterial, raycaster, ray, fvA, fvB, fvC, intersectionPoint ); + 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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - if ( intersection ) { + 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}"; - if ( uvs && uvs[ f ] ) { + 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 \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\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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - var uvs_f = uvs[ f ]; - uvA.copy( uvs_f[ 0 ] ); - uvB.copy( uvs_f[ 1 ] ); - uvC.copy( uvs_f[ 2 ] ); + 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#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\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}"; - intersection.uv = Triangle.getUV( intersectionPoint, fvA, fvB, fvC, uvA, uvB, uvC, new Vector2() ); + 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 \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_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\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}"; - intersection.face = face; - intersection.faceIndex = f; - intersects.push( intersection ); + var meshmatcap_frag = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\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 \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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\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#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 \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#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\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\tvViewPosition = - mvPosition.xyz;\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 \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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\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#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 \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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\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 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 \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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\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#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 \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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\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}"; - clone: function () { + var meshphysical_frag = "#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSMISSION\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSMISSION\n\tuniform float transmission;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#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\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#ifdef TRANSMISSION\n\t\tfloat totalTransmission = transmission;\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\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#ifdef TRANSMISSION\n\t\tdiffuseColor.a *= saturate( 1. - totalTransmission + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) );\n\t#endif\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - return new this.constructor( this.geometry, this.material ).copy( this ); + var meshphysical_vert = "#define STANDARD\nvarying vec3 vViewPosition;\n#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\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#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\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 normal_frag = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#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\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 normal_vert = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#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\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#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\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}"; - /** - * @author mrdoob / http://mrdoob.com/ - */ + var points_frag = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - function WebGLBackground( renderer, state, objects, premultipliedAlpha ) { + 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 clearColor = new Color( 0x000000 ); - var clearAlpha = 0; + 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 planeMesh; - var boxMesh; + 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}"; - function render( renderList, scene, camera, forceClear ) { + var sprite_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\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n}"; - var background = scene.background; + 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}"; - if ( background === null ) { + var ShaderChunk = { + alphamap_fragment: alphamap_fragment, + alphamap_pars_fragment: alphamap_pars_fragment, + alphatest_fragment: alphatest_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, + 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, + 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, + transmissionmap_fragment: transmissionmap_fragment, + transmissionmap_pars_fragment: transmissionmap_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, - setClear( clearColor, clearAlpha ); + 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, + meshtoon_frag: meshtoon_frag, + meshtoon_vert: meshtoon_vert, + meshphong_frag: meshphong_frag, + meshphong_vert: meshphong_vert, + meshphysical_frag: meshphysical_frag, + meshphysical_vert: meshphysical_vert, + normal_frag: normal_frag, + normal_vert: normal_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 + }; - } else if ( background && background.isColor ) { + var ShaderLib = { - setClear( background, 1 ); - forceClear = true; + basic: { - } + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.specularmap, + UniformsLib.envmap, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.fog + ] ), - if ( renderer.autoClear || forceClear ) { + vertexShader: ShaderChunk.meshbasic_vert, + fragmentShader: ShaderChunk.meshbasic_frag - renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); + }, - } + lambert: { - if ( background && ( background.isCubeTexture || background.isWebGLRenderTargetCube ) ) { + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.specularmap, + UniformsLib.envmap, + UniformsLib.aomap, + UniformsLib.lightmap, + UniformsLib.emissivemap, + UniformsLib.fog, + UniformsLib.lights, + { + emissive: { value: new Color( 0x000000 ) } + } + ] ), - if ( boxMesh === undefined ) { + vertexShader: ShaderChunk.meshlambert_vert, + fragmentShader: ShaderChunk.meshlambert_frag - boxMesh = new Mesh( - new BoxBufferGeometry( 1, 1, 1 ), - new ShaderMaterial( { - type: 'BackgroundCubeMaterial', - uniforms: UniformsUtils.clone( ShaderLib.cube.uniforms ), - vertexShader: ShaderLib.cube.vertexShader, - fragmentShader: ShaderLib.cube.fragmentShader, - side: BackSide, - depthTest: true, - depthWrite: false, - fog: false - } ) - ); + }, - boxMesh.geometry.removeAttribute( 'normal' ); - boxMesh.geometry.removeAttribute( 'uv' ); + phong: { - boxMesh.onBeforeRender = function ( renderer, scene, camera ) { + 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 } + } + ] ), - this.matrixWorld.copyPosition( camera.matrixWorld ); + vertexShader: ShaderChunk.meshphong_vert, + fragmentShader: ShaderChunk.meshphong_frag - }; + }, - objects.update( boxMesh ); + 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 } + ] ), - boxMesh.material.uniforms.tCube.value = ( background.isWebGLRenderTargetCube ) ? background.texture : background; - boxMesh.material.uniforms.tFlip.value = ( background.isWebGLRenderTargetCube ) ? 1 : - 1; + vertexShader: ShaderChunk.meshphysical_vert, + fragmentShader: ShaderChunk.meshphysical_frag - // push to the pre-sorted opaque render list - renderList.push( boxMesh, boxMesh.geometry, boxMesh.material, 0, null ); + }, - } else if ( background && background.isTexture ) { + toon: { - if ( planeMesh === undefined ) { + 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 ) } + } + ] ), - planeMesh = new Mesh( - new PlaneBufferGeometry( 2, 2 ), - new ShaderMaterial( { - type: 'BackgroundMaterial', - uniforms: UniformsUtils.clone( ShaderLib.background.uniforms ), - vertexShader: ShaderLib.background.vertexShader, - fragmentShader: ShaderLib.background.fragmentShader, - side: FrontSide, - depthTest: true, - depthWrite: false, - fog: false - } ) - ); + vertexShader: ShaderChunk.meshtoon_vert, + fragmentShader: ShaderChunk.meshtoon_frag - planeMesh.geometry.removeAttribute( 'normal' ); + }, - objects.update( planeMesh ); + matcap: { + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + UniformsLib.fog, + { + matcap: { value: null } } + ] ), - planeMesh.material.uniforms.t2D.value = background; + vertexShader: ShaderChunk.meshmatcap_vert, + fragmentShader: ShaderChunk.meshmatcap_frag - if ( background.matrixAutoUpdate === true ) { + }, - background.updateMatrix(); + points: { - } + uniforms: mergeUniforms( [ + UniformsLib.points, + UniformsLib.fog + ] ), - planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); + vertexShader: ShaderChunk.points_vert, + fragmentShader: ShaderChunk.points_frag - // push to the pre-sorted opaque render list - renderList.push( planeMesh, planeMesh.geometry, planeMesh.material, 0, null ); + }, - } + dashed: { - } + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.fog, + { + scale: { value: 1 }, + dashSize: { value: 1 }, + totalSize: { value: 2 } + } + ] ), - function setClear( color, alpha ) { + vertexShader: ShaderChunk.linedashed_vert, + fragmentShader: ShaderChunk.linedashed_frag - state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha ); + }, - } + depth: { - return { + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.displacementmap + ] ), - getClearColor: function () { + vertexShader: ShaderChunk.depth_vert, + fragmentShader: ShaderChunk.depth_frag - return clearColor; + }, - }, - setClearColor: function ( color, alpha ) { + normal: { - clearColor.set( color ); - clearAlpha = alpha !== undefined ? alpha : 1; - setClear( clearColor, clearAlpha ); + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.bumpmap, + UniformsLib.normalmap, + UniformsLib.displacementmap, + { + opacity: { value: 1.0 } + } + ] ), - }, - getClearAlpha: function () { + vertexShader: ShaderChunk.normal_vert, + fragmentShader: ShaderChunk.normal_frag - return clearAlpha; + }, - }, - setClearAlpha: function ( alpha ) { + sprite: { - clearAlpha = alpha; - setClear( clearColor, clearAlpha ); + uniforms: mergeUniforms( [ + UniformsLib.sprite, + UniformsLib.fog + ] ), - }, - render: render + vertexShader: ShaderChunk.sprite_vert, + fragmentShader: ShaderChunk.sprite_frag - }; + }, - } + background: { - /** - * @author mrdoob / http://mrdoob.com/ - */ + uniforms: { + uvTransform: { value: new Matrix3() }, + t2D: { value: null }, + }, - function WebGLBufferRenderer( gl, extensions, info, capabilities ) { + vertexShader: ShaderChunk.background_vert, + fragmentShader: ShaderChunk.background_frag - var mode; + }, + /* ------------------------------------------------------------------------- + // Cube map shader + ------------------------------------------------------------------------- */ - function setMode( value ) { + cube: { - mode = value; + uniforms: mergeUniforms( [ + UniformsLib.envmap, + { + opacity: { value: 1.0 } + } + ] ), - } + vertexShader: ShaderChunk.cube_vert, + fragmentShader: ShaderChunk.cube_frag - function render( start, count ) { + }, - gl.drawArrays( mode, start, count ); + equirect: { - info.update( count, mode ); + uniforms: { + tEquirect: { value: null }, + }, - } + vertexShader: ShaderChunk.equirect_vert, + fragmentShader: ShaderChunk.equirect_frag - function renderInstances( geometry, start, count ) { + }, - var extension; + distanceRGBA: { - if ( capabilities.isWebGL2 ) { + uniforms: mergeUniforms( [ + UniformsLib.common, + UniformsLib.displacementmap, + { + referencePosition: { value: new Vector3() }, + nearDistance: { value: 1 }, + farDistance: { value: 1000 } + } + ] ), - extension = gl; + vertexShader: ShaderChunk.distanceRGBA_vert, + fragmentShader: ShaderChunk.distanceRGBA_frag - } else { + }, - extension = extensions.get( 'ANGLE_instanced_arrays' ); + shadow: { - if ( extension === null ) { + uniforms: mergeUniforms( [ + UniformsLib.lights, + UniformsLib.fog, + { + color: { value: new Color( 0x00000 ) }, + opacity: { value: 1.0 } + } ] ), - console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + 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 }, + sheen: { value: new Color( 0x000000 ) }, + transmission: { value: 0 }, + transmissionMap: { value: null }, } + ] ), - extension[ capabilities.isWebGL2 ? 'drawArraysInstanced' : 'drawArraysInstancedANGLE' ]( mode, start, count, geometry.maxInstancedCount ); + vertexShader: ShaderChunk.meshphysical_vert, + fragmentShader: ShaderChunk.meshphysical_frag - info.update( count, mode, geometry.maxInstancedCount ); + }; - } + function WebGLBackground( renderer, state, objects, premultipliedAlpha ) { - // + var clearColor = new Color( 0x000000 ); + var clearAlpha = 0; - this.setMode = setMode; - this.render = render; - this.renderInstances = renderInstances; + var planeMesh; + var boxMesh; - } + var currentBackground = null; + var currentBackgroundVersion = 0; + var currentTonemapping = null; - /** - * @author mrdoob / http://mrdoob.com/ - */ + function render( renderList, scene, camera, forceClear ) { - function WebGLCapabilities( gl, extensions, parameters ) { + var background = scene.isScene === true ? scene.background : null; - var maxAnisotropy; + // Ignore background in AR + // TODO: Reconsider this. - function getMaxAnisotropy() { + var xr = renderer.xr; + var session = xr.getSession && xr.getSession(); - if ( maxAnisotropy !== undefined ) return maxAnisotropy; + if ( session && session.environmentBlendMode === 'additive' ) { - var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + background = null; - if ( extension !== null ) { + } - maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); + if ( background === null ) { - } else { + setClear( clearColor, clearAlpha ); - maxAnisotropy = 0; + } else if ( background && background.isColor ) { + + setClear( background, 1 ); + forceClear = true; } - return maxAnisotropy; + if ( renderer.autoClear || forceClear ) { - } + renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); - function getMaxPrecision( precision ) { + } - if ( precision === 'highp' ) { + if ( background && ( background.isCubeTexture || background.isWebGLCubeRenderTarget || background.mapping === CubeUVReflectionMapping ) ) { - if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { + if ( boxMesh === undefined ) { - return 'highp'; + boxMesh = new Mesh( + new BoxBufferGeometry( 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' ); - precision = 'mediump'; + boxMesh.onBeforeRender = function ( renderer, scene, camera ) { - } + this.matrixWorld.copyPosition( camera.matrixWorld ); - if ( precision === 'mediump' ) { + }; - if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { + // enable code injection for non-built-in material + Object.defineProperty( boxMesh.material, 'envMap', { - return 'mediump'; + get: function () { - } + return this.uniforms.envMap.value; - } + } - return 'lowp'; + } ); - } + objects.update( boxMesh ); - var isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext; + } - var precision = parameters.precision !== undefined ? parameters.precision : 'highp'; - var maxPrecision = getMaxPrecision( precision ); + var texture = background.isWebGLCubeRenderTarget ? background.texture : background; - if ( maxPrecision !== precision ) { + boxMesh.material.uniforms.envMap.value = texture; + boxMesh.material.uniforms.flipEnvMap.value = texture.isCubeTexture ? - 1 : 1; - console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); - precision = maxPrecision; + if ( currentBackground !== background || + currentBackgroundVersion !== texture.version || + currentTonemapping !== renderer.toneMapping ) { - } + boxMesh.material.needsUpdate = true; - var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; + currentBackground = background; + currentBackgroundVersion = texture.version; + currentTonemapping = renderer.toneMapping; - var maxTextures = gl.getParameter( 34930 ); - var maxVertexTextures = gl.getParameter( 35660 ); - var maxTextureSize = gl.getParameter( 3379 ); - var maxCubemapSize = gl.getParameter( 34076 ); + } - var maxAttributes = gl.getParameter( 34921 ); - var maxVertexUniforms = gl.getParameter( 36347 ); - var maxVaryings = gl.getParameter( 36348 ); - var maxFragmentUniforms = gl.getParameter( 36349 ); + // push to the pre-sorted opaque render list + renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null ); - var vertexTextures = maxVertexTextures > 0; - var floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' ); - var floatVertexTextures = vertexTextures && floatFragmentTextures; + } else if ( background && background.isTexture ) { - return { + if ( planeMesh === undefined ) { - isWebGL2: isWebGL2, + planeMesh = new Mesh( + new PlaneBufferGeometry( 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 + } ) + ); - getMaxAnisotropy: getMaxAnisotropy, - getMaxPrecision: getMaxPrecision, + planeMesh.geometry.deleteAttribute( 'normal' ); - precision: precision, - logarithmicDepthBuffer: logarithmicDepthBuffer, + // enable code injection for non-built-in material + Object.defineProperty( planeMesh.material, 'map', { - maxTextures: maxTextures, - maxVertexTextures: maxVertexTextures, - maxTextureSize: maxTextureSize, - maxCubemapSize: maxCubemapSize, + get: function () { - maxAttributes: maxAttributes, - maxVertexUniforms: maxVertexUniforms, - maxVaryings: maxVaryings, - maxFragmentUniforms: maxFragmentUniforms, + return this.uniforms.t2D.value; - vertexTextures: vertexTextures, - floatFragmentTextures: floatFragmentTextures, - floatVertexTextures: floatVertexTextures + } - }; + } ); - } + objects.update( planeMesh ); - /** - * @author tschw - */ + } - function WebGLClipping() { + planeMesh.material.uniforms.t2D.value = background; - var scope = this, + if ( background.matrixAutoUpdate === true ) { - globalState = null, - numGlobalPlanes = 0, - localClippingEnabled = false, - renderingShadows = false, + background.updateMatrix(); - plane = new Plane(), - viewNormalMatrix = new Matrix3(), + } - uniform = { value: null, needsUpdate: false }; + planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); - this.uniform = uniform; - this.numPlanes = 0; - this.numIntersection = 0; + if ( currentBackground !== background || + currentBackgroundVersion !== background.version || + currentTonemapping !== renderer.toneMapping ) { - this.init = function ( planes, enableLocalClipping, camera ) { + planeMesh.material.needsUpdate = true; - var 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; + currentBackground = background; + currentBackgroundVersion = background.version; + currentTonemapping = renderer.toneMapping; - localClippingEnabled = enableLocalClipping; + } - globalState = projectPlanes( planes, camera, 0 ); - numGlobalPlanes = planes.length; - return enabled; + // push to the pre-sorted opaque render list + renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null ); - }; + } - this.beginShadows = function () { + } - renderingShadows = true; - projectPlanes( null ); + function setClear( color, alpha ) { - }; + state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha ); - this.endShadows = function () { + } - renderingShadows = false; - resetGlobalState(); + return { - }; + getClearColor: function () { - this.setState = function ( planes, clipIntersection, clipShadows, camera, cache, fromCache ) { + return clearColor; - if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { + }, + setClearColor: function ( color, alpha ) { - // there's no local clipping + clearColor.set( color ); + clearAlpha = alpha !== undefined ? alpha : 1; + setClear( clearColor, clearAlpha ); - if ( renderingShadows ) { + }, + getClearAlpha: function () { - // there's no global clipping + return clearAlpha; - projectPlanes( null ); + }, + setClearAlpha: function ( alpha ) { - } else { + clearAlpha = alpha; + setClear( clearColor, clearAlpha ); - resetGlobalState(); + }, + render: render - } + }; - } else { + } - var nGlobal = renderingShadows ? 0 : numGlobalPlanes, - lGlobal = nGlobal * 4, + function WebGLBindingStates( gl, extensions, attributes, capabilities ) { - dstArray = cache.clippingState || null; + var maxVertexAttributes = gl.getParameter( 34921 ); - uniform.value = dstArray; // ensure unique state + var extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); + var vaoAvailable = capabilities.isWebGL2 || extension !== null; - dstArray = projectPlanes( planes, camera, lGlobal, fromCache ); + var bindingStates = {}; - for ( var i = 0; i !== lGlobal; ++ i ) { + var defaultState = createBindingState( null ); + var currentState = defaultState; - dstArray[ i ] = globalState[ i ]; + function setup( object, material, program, geometry, index ) { - } + var updateBuffers = false; - cache.clippingState = dstArray; - this.numIntersection = clipIntersection ? this.numPlanes : 0; - this.numPlanes += nGlobal; + if ( vaoAvailable ) { - } + var state = getBindingState( geometry, program, material ); + if ( currentState !== state ) { - }; + currentState = state; + bindVertexArrayObject( currentState.object ); - function resetGlobalState() { + } - if ( uniform.value !== globalState ) { + updateBuffers = needsUpdate( geometry ); - uniform.value = globalState; - uniform.needsUpdate = numGlobalPlanes > 0; + if ( updateBuffers ) { saveCache( geometry ); } - } + } else { - scope.numPlanes = numGlobalPlanes; - scope.numIntersection = 0; + var wireframe = ( material.wireframe === true ); - } + if ( currentState.geometry !== geometry.id || + currentState.program !== program.id || + currentState.wireframe !== wireframe ) { - function projectPlanes( planes, camera, dstOffset, skipTransform ) { + currentState.geometry = geometry.id; + currentState.program = program.id; + currentState.wireframe = wireframe; - var nPlanes = planes !== null ? planes.length : 0, - dstArray = null; + updateBuffers = true; - if ( nPlanes !== 0 ) { + } - dstArray = uniform.value; + } - if ( skipTransform !== true || dstArray === null ) { + if ( object.isInstancedMesh === true ) { - var flatSize = dstOffset + nPlanes * 4, - viewMatrix = camera.matrixWorldInverse; + updateBuffers = true; - viewNormalMatrix.getNormalMatrix( viewMatrix ); + } - if ( dstArray === null || dstArray.length < flatSize ) { + if ( index !== null ) { - dstArray = new Float32Array( flatSize ); + attributes.update( index, 34963 ); - } + } - for ( var i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { + if ( updateBuffers ) { - plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); + setupVertexAttributes( object, material, program, geometry ); - plane.normal.toArray( dstArray, i4 ); - dstArray[ i4 + 3 ] = plane.constant; + if ( index !== null ) { - } + gl.bindBuffer( 34963, attributes.get( index ).buffer ); } - uniform.value = dstArray; - uniform.needsUpdate = true; - } - scope.numPlanes = nPlanes; - - return dstArray; - } - } - - /** - * @author mrdoob / http://mrdoob.com/ - */ + function createVertexArrayObject() { - function WebGLExtensions( gl ) { + if ( capabilities.isWebGL2 ) { return gl.createVertexArray(); } - var extensions = {}; + return extension.createVertexArrayOES(); - return { + } - get: function ( name ) { + function bindVertexArrayObject( vao ) { - if ( extensions[ name ] !== undefined ) { + if ( capabilities.isWebGL2 ) { return gl.bindVertexArray( vao ); } - return extensions[ name ]; + return extension.bindVertexArrayOES( vao ); - } + } - var extension; + function deleteVertexArrayObject( vao ) { - switch ( name ) { + if ( capabilities.isWebGL2 ) { return gl.deleteVertexArray( vao ); } - case 'WEBGL_depth_texture': - extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); - break; + return extension.deleteVertexArrayOES( vao ); - 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; + function getBindingState( geometry, program, material ) { - case 'WEBGL_compressed_texture_pvrtc': - extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); - break; + var wireframe = ( material.wireframe === true ); - default: - extension = gl.getExtension( name ); + var programMap = bindingStates[ geometry.id ]; - } + if ( programMap === undefined ) { - if ( extension === null ) { + programMap = {}; + bindingStates[ geometry.id ] = programMap; - console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); + } - } + var stateMap = programMap[ program.id ]; - extensions[ name ] = extension; + if ( stateMap === undefined ) { - return extension; + stateMap = {}; + programMap[ program.id ] = stateMap; } - }; + var state = stateMap[ wireframe ]; - } + if ( state === undefined ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + state = createBindingState( createVertexArrayObject() ); + stateMap[ wireframe ] = state; + + } - function WebGLGeometries( gl, attributes, info ) { + return state; - var geometries = {}; - var wireframeAttributes = {}; + } - function onGeometryDispose( event ) { + function createBindingState( vao ) { - var geometry = event.target; - var buffergeometry = geometries[ geometry.id ]; + var newAttributes = []; + var enabledAttributes = []; + var attributeDivisors = []; - if ( buffergeometry.index !== null ) { + for ( var i = 0; i < maxVertexAttributes; i ++ ) { - attributes.remove( buffergeometry.index ); + newAttributes[ i ] = 0; + enabledAttributes[ i ] = 0; + attributeDivisors[ i ] = 0; } - for ( var name in buffergeometry.attributes ) { + return { - attributes.remove( buffergeometry.attributes[ name ] ); + // for backward compatibility on non-VAO support browser + geometry: null, + program: null, + wireframe: false, - } + newAttributes: newAttributes, + enabledAttributes: enabledAttributes, + attributeDivisors: attributeDivisors, + object: vao, + attributes: {} - geometry.removeEventListener( 'dispose', onGeometryDispose ); + }; + + } - delete geometries[ geometry.id ]; + function needsUpdate( geometry ) { - var attribute = wireframeAttributes[ buffergeometry.id ]; + var cachedAttributes = currentState.attributes; + var geometryAttributes = geometry.attributes; - if ( attribute ) { + if ( Object.keys( cachedAttributes ).length !== Object.keys( geometryAttributes ).length ) { return true; } - attributes.remove( attribute ); - delete wireframeAttributes[ buffergeometry.id ]; + for ( var key in geometryAttributes ) { - } + var cachedAttribute = cachedAttributes[ key ]; + var geometryAttribute = geometryAttributes[ key ]; - // + if ( cachedAttribute.attribute !== geometryAttribute ) { return true; } - info.memory.geometries --; + if ( cachedAttribute.data !== geometryAttribute.data ) { return true; } - } + } - function get( object, geometry ) { + return false; - var buffergeometry = geometries[ geometry.id ]; + } - if ( buffergeometry ) return buffergeometry; + function saveCache( geometry ) { - geometry.addEventListener( 'dispose', onGeometryDispose ); + var cache = {}; + var attributes = geometry.attributes; - if ( geometry.isBufferGeometry ) { + for ( var key in attributes ) { - buffergeometry = geometry; + var attribute = attributes[ key ]; - } else if ( geometry.isGeometry ) { + var data = {}; + data.attribute = attribute; - if ( geometry._bufferGeometry === undefined ) { + if ( attribute.data ) { - geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); + data.data = attribute.data; } - buffergeometry = geometry._bufferGeometry; + cache[ key ] = data; } - geometries[ geometry.id ] = buffergeometry; - - info.memory.geometries ++; - - return buffergeometry; + currentState.attributes = cache; } - function update( geometry ) { + function initAttributes() { - var index = geometry.index; - var geometryAttributes = geometry.attributes; + var newAttributes = currentState.newAttributes; - if ( index !== null ) { + for ( var i = 0, il = newAttributes.length; i < il; i ++ ) { - attributes.update( index, 34963 ); + newAttributes[ i ] = 0; } - for ( var name in geometryAttributes ) { + } - attributes.update( geometryAttributes[ name ], 34962 ); + function enableAttribute( attribute ) { - } + enableAttributeAndDivisor( attribute, 0 ); - // morph targets + } - var morphAttributes = geometry.morphAttributes; + function enableAttributeAndDivisor( attribute, meshPerAttribute ) { - for ( var name in morphAttributes ) { + var newAttributes = currentState.newAttributes; + var enabledAttributes = currentState.enabledAttributes; + var attributeDivisors = currentState.attributeDivisors; - var array = morphAttributes[ name ]; + newAttributes[ attribute ] = 1; - for ( var i = 0, l = array.length; i < l; i ++ ) { + if ( enabledAttributes[ attribute ] === 0 ) { - attributes.update( array[ i ], 34962 ); + gl.enableVertexAttribArray( attribute ); + enabledAttributes[ attribute ] = 1; - } + } + + if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { + + var extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); + + extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); + attributeDivisors[ attribute ] = meshPerAttribute; } } - function getWireframeAttribute( geometry ) { - - var attribute = wireframeAttributes[ geometry.id ]; + function disableUnusedAttributes() { - if ( attribute ) return attribute; + var newAttributes = currentState.newAttributes; + var enabledAttributes = currentState.enabledAttributes; - var indices = []; + for ( var i = 0, il = enabledAttributes.length; i < il; i ++ ) { - var geometryIndex = geometry.index; - var geometryAttributes = geometry.attributes; + if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { - // console.time( 'wireframe' ); + gl.disableVertexAttribArray( i ); + enabledAttributes[ i ] = 0; - if ( geometryIndex !== null ) { + } - var array = geometryIndex.array; + } - for ( var i = 0, l = array.length; i < l; i += 3 ) { + } - var a = array[ i + 0 ]; - var b = array[ i + 1 ]; - var c = array[ i + 2 ]; + function vertexAttribPointer( index, size, type, normalized, stride, offset ) { - indices.push( a, b, b, c, c, a ); + if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) { - } + gl.vertexAttribIPointer( index, size, type, stride, offset ); } else { - var array = geometryAttributes.position.array; + gl.vertexAttribPointer( index, size, type, normalized, stride, offset ); + + } - for ( var i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { + } - var a = i + 0; - var b = i + 1; - var c = i + 2; + function setupVertexAttributes( object, material, program, geometry ) { - indices.push( a, b, b, c, c, a ); + if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) { - } + if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) { return; } } - // console.timeEnd( 'wireframe' ); + initAttributes(); - attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); + var geometryAttributes = geometry.attributes; - attributes.update( attribute, 34963 ); + var programAttributes = program.getAttributes(); - wireframeAttributes[ geometry.id ] = attribute; + var materialDefaultAttributeValues = material.defaultAttributeValues; - return attribute; + for ( var name in programAttributes ) { - } + var programAttribute = programAttributes[ name ]; - return { + if ( programAttribute >= 0 ) { - get: get, - update: update, + var geometryAttribute = geometryAttributes[ name ]; - getWireframeAttribute: getWireframeAttribute + if ( geometryAttribute !== undefined ) { - }; + var normalized = geometryAttribute.normalized; + var size = geometryAttribute.itemSize; - } + var attribute = attributes.get( geometryAttribute ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + // TODO Attribute may not be available on context restore - function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { + if ( attribute === undefined ) { continue; } - var mode; + var buffer = attribute.buffer; + var type = attribute.type; + var bytesPerElement = attribute.bytesPerElement; - function setMode( value ) { + if ( geometryAttribute.isInterleavedBufferAttribute ) { - mode = value; + var data = geometryAttribute.data; + var stride = data.stride; + var offset = geometryAttribute.offset; - } + if ( data && data.isInstancedInterleavedBuffer ) { - var type, bytesPerElement; + enableAttributeAndDivisor( programAttribute, data.meshPerAttribute ); - function setIndex( value ) { + if ( geometry._maxInstanceCount === undefined ) { - type = value.type; - bytesPerElement = value.bytesPerElement; + geometry._maxInstanceCount = data.meshPerAttribute * data.count; - } + } - function render( start, count ) { + } else { - gl.drawElements( mode, count, type, start * bytesPerElement ); + enableAttribute( programAttribute ); - info.update( count, mode ); + } - } + gl.bindBuffer( 34962, buffer ); + vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement ); - function renderInstances( geometry, start, count ) { + } else { - var extension; + if ( geometryAttribute.isInstancedBufferAttribute ) { - if ( capabilities.isWebGL2 ) { + enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute ); - extension = gl; + if ( geometry._maxInstanceCount === undefined ) { - } else { + geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; - var extension = extensions.get( 'ANGLE_instanced_arrays' ); + } - if ( extension === null ) { + } else { - console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + enableAttribute( programAttribute ); - } + } - } + gl.bindBuffer( 34962, buffer ); + vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 ); - extension[ capabilities.isWebGL2 ? 'drawElementsInstanced' : 'drawElementsInstancedANGLE' ]( mode, count, type, start * bytesPerElement, geometry.maxInstancedCount ); + } - info.update( count, mode, geometry.maxInstancedCount ); + } else if ( name === 'instanceMatrix' ) { - } + var attribute$1 = attributes.get( object.instanceMatrix ); - // + // TODO Attribute may not be available on context restore - this.setMode = setMode; - this.setIndex = setIndex; - this.render = render; - this.renderInstances = renderInstances; + if ( attribute$1 === undefined ) { continue; } - } + var buffer$1 = attribute$1.buffer; + var type$1 = attribute$1.type; - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + enableAttributeAndDivisor( programAttribute + 0, 1 ); + enableAttributeAndDivisor( programAttribute + 1, 1 ); + enableAttributeAndDivisor( programAttribute + 2, 1 ); + enableAttributeAndDivisor( programAttribute + 3, 1 ); - function WebGLInfo( gl ) { + gl.bindBuffer( 34962, buffer$1 ); - var memory = { - geometries: 0, - textures: 0 - }; + gl.vertexAttribPointer( programAttribute + 0, 4, type$1, false, 64, 0 ); + gl.vertexAttribPointer( programAttribute + 1, 4, type$1, false, 64, 16 ); + gl.vertexAttribPointer( programAttribute + 2, 4, type$1, false, 64, 32 ); + gl.vertexAttribPointer( programAttribute + 3, 4, type$1, false, 64, 48 ); - var render = { - frame: 0, - calls: 0, - triangles: 0, - points: 0, - lines: 0 - }; + } else if ( materialDefaultAttributeValues !== undefined ) { - function update( count, mode, instanceCount ) { + var value = materialDefaultAttributeValues[ name ]; - instanceCount = instanceCount || 1; + if ( value !== undefined ) { - render.calls ++; + switch ( value.length ) { - switch ( mode ) { + case 2: + gl.vertexAttrib2fv( programAttribute, value ); + break; - case 4: - render.triangles += instanceCount * ( count / 3 ); - break; + case 3: + gl.vertexAttrib3fv( programAttribute, value ); + break; - case 5: - case 6: - render.triangles += instanceCount * ( count - 2 ); - break; + case 4: + gl.vertexAttrib4fv( programAttribute, value ); + break; - case 1: - render.lines += instanceCount * ( count / 2 ); - break; + default: + gl.vertexAttrib1fv( programAttribute, value ); - 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; + disableUnusedAttributes(); } - return { - memory: memory, - render: render, - programs: null, - autoReset: true, - reset: reset, - update: update - }; - - } - - /** - * @author mrdoob / http://mrdoob.com/ - */ - - function absNumericalSort( a, b ) { - - return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); - - } - - function WebGLMorphtargets( gl ) { + function dispose() { - var influencesList = {}; - var morphInfluences = new Float32Array( 8 ); + reset(); - function update( object, geometry, material, program ) { + for ( var geometryId in bindingStates ) { - var objectInfluences = object.morphTargetInfluences; + var programMap = bindingStates[ geometryId ]; - var length = objectInfluences.length; + for ( var programId in programMap ) { - var influences = influencesList[ geometry.id ]; + var stateMap = programMap[ programId ]; - if ( influences === undefined ) { + for ( var wireframe in stateMap ) { - // initialise list + deleteVertexArrayObject( stateMap[ wireframe ].object ); - influences = []; + delete stateMap[ wireframe ]; - for ( var i = 0; i < length; i ++ ) { + } - influences[ i ] = [ i, 0 ]; + delete programMap[ programId ]; } - influencesList[ geometry.id ] = influences; + delete bindingStates[ geometryId ]; } - var morphTargets = material.morphTargets && geometry.morphAttributes.position; - var morphNormals = material.morphNormals && geometry.morphAttributes.normal; - - // Remove current morphAttributes + } - for ( var i = 0; i < length; i ++ ) { + function releaseStatesOfGeometry( geometry ) { - var influence = influences[ i ]; + if ( bindingStates[ geometry.id ] === undefined ) { return; } - if ( influence[ 1 ] !== 0 ) { + var programMap = bindingStates[ geometry.id ]; - if ( morphTargets ) geometry.removeAttribute( 'morphTarget' + i ); - if ( morphNormals ) geometry.removeAttribute( 'morphNormal' + i ); + for ( var programId in programMap ) { - } + var stateMap = programMap[ programId ]; - } + for ( var wireframe in stateMap ) { - // Collect influences + deleteVertexArrayObject( stateMap[ wireframe ].object ); - for ( var i = 0; i < length; i ++ ) { + delete stateMap[ wireframe ]; - var influence = influences[ i ]; + } - influence[ 0 ] = i; - influence[ 1 ] = objectInfluences[ i ]; + delete programMap[ programId ]; } - influences.sort( absNumericalSort ); + delete bindingStates[ geometry.id ]; - // Add morphAttributes + } - for ( var i = 0; i < 8; i ++ ) { + function releaseStatesOfProgram( program ) { - var influence = influences[ i ]; + for ( var geometryId in bindingStates ) { - if ( influence ) { + var programMap = bindingStates[ geometryId ]; - var index = influence[ 0 ]; - var value = influence[ 1 ]; + if ( programMap[ program.id ] === undefined ) { continue; } - if ( value ) { + var stateMap = programMap[ program.id ]; - if ( morphTargets ) geometry.addAttribute( 'morphTarget' + i, morphTargets[ index ] ); - if ( morphNormals ) geometry.addAttribute( 'morphNormal' + i, morphNormals[ index ] ); + for ( var wireframe in stateMap ) { - morphInfluences[ i ] = value; - continue; + deleteVertexArrayObject( stateMap[ wireframe ].object ); - } + delete stateMap[ wireframe ]; } - morphInfluences[ i ] = 0; + delete programMap[ program.id ]; } - program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); - } - return { + function reset() { - update: update + resetDefaultState(); - }; + if ( currentState === defaultState ) { return; } - } + currentState = defaultState; + bindVertexArrayObject( currentState.object ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function WebGLObjects( geometries, info ) { + // for backward-compatilibity - var updateList = {}; + function resetDefaultState() { - function update( object ) { + defaultState.geometry = null; + defaultState.program = null; + defaultState.wireframe = false; - var frame = info.render.frame; + } - var geometry = object.geometry; - var buffergeometry = geometries.get( object, geometry ); + return { - // Update once per frame + setup: setup, + reset: reset, + resetDefaultState: resetDefaultState, + dispose: dispose, + releaseStatesOfGeometry: releaseStatesOfGeometry, + releaseStatesOfProgram: releaseStatesOfProgram, - if ( updateList[ buffergeometry.id ] !== frame ) { + initAttributes: initAttributes, + enableAttribute: enableAttribute, + disableUnusedAttributes: disableUnusedAttributes - if ( geometry.isGeometry ) { + }; - buffergeometry.updateFromObject( object ); + } - } + function WebGLBufferRenderer( gl, extensions, info, capabilities ) { - geometries.update( buffergeometry ); + var isWebGL2 = capabilities.isWebGL2; - updateList[ buffergeometry.id ] = frame; + var mode; - } + function setMode( value ) { - return buffergeometry; + mode = value; } - function dispose() { + function render( start, count ) { + + gl.drawArrays( mode, start, count ); - updateList = {}; + info.update( count, mode, 1 ); } - return { + function renderInstances( start, count, primcount ) { - update: update, - dispose: dispose + if ( primcount === 0 ) { return; } - }; + var extension, methodName; - } + if ( isWebGL2 ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + extension = gl; + methodName = 'drawArraysInstanced'; - function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { + } else { - images = images !== undefined ? images : []; - mapping = mapping !== undefined ? mapping : CubeReflectionMapping; + extension = extensions.get( 'ANGLE_instanced_arrays' ); + methodName = 'drawArraysInstancedANGLE'; - Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + if ( extension === null ) { - this.flipY = false; + console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; - } + } - CubeTexture.prototype = Object.create( Texture.prototype ); - CubeTexture.prototype.constructor = CubeTexture; + } - CubeTexture.prototype.isCubeTexture = true; + extension[ methodName ]( mode, start, count, primcount ); - Object.defineProperty( CubeTexture.prototype, 'images', { + info.update( count, mode, primcount ); - get: function () { + } - return this.image; + // - }, + this.setMode = setMode; + this.render = render; + this.renderInstances = renderInstances; - set: function ( value ) { + } - this.image = value; + function WebGLCapabilities( gl, extensions, parameters ) { - } + var maxAnisotropy; - } ); + function getMaxAnisotropy() { - /** - * @author Artur Trzesiok - */ + if ( maxAnisotropy !== undefined ) { return maxAnisotropy; } - function DataTexture3D( data, width, height, depth ) { + var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - // We're going to add .setXXX() methods for setting properties later. - // Users can still set in DataTexture3D directly. - // - // var texture = new THREE.DataTexture3D( data, width, height, depth ); - // texture.anisotropy = 16; - // - // See #14839 + if ( extension !== null ) { - Texture.call( this, null ); + maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); - this.image = { data: data, width: width, height: height, depth: depth }; + } else { - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + maxAnisotropy = 0; - this.generateMipmaps = false; - this.flipY = false; + } - } + return maxAnisotropy; - DataTexture3D.prototype = Object.create( Texture.prototype ); - DataTexture3D.prototype.constructor = DataTexture3D; - DataTexture3D.prototype.isDataTexture3D = true; + } - /** - * @author tschw - * @author Mugen87 / https://github.com/Mugen87 - * @author mrdoob / http://mrdoob.com/ - * - * 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, renderer )'. - * - * - * 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, [renderer] ) - * - * uploads a uniform value(s) - * the 'renderer' parameter is needed for sampler uniforms - * - * - * Static methods of the top-level container (renderer factorizations): - * - * .upload( gl, seq, values, renderer ) - * - * 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 (renderer factorizations): - * - * .setValue( gl, name, value ) - * - * sets uniform with name 'name' to 'value' - * - * .set( gl, obj, prop ) - * - * sets uniform from object and property with same name than uniform - * - * .setOptional( gl, obj, prop ) - * - * like .set for an optional property of the object - * - */ + function getMaxPrecision( precision ) { - var emptyTexture = new Texture(); - var emptyTexture3d = new DataTexture3D(); - var emptyCubeTexture = new CubeTexture(); + if ( precision === 'highp' ) { - // --- Base for inner nodes (including the root) --- + if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && + gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { - function UniformContainer() { + return 'highp'; - this.seq = []; - this.map = {}; + } - } + precision = 'mediump'; - // --- Utilities --- + } - // Array Caches (provide typed arrays for temporary by size) + if ( precision === 'mediump' ) { - var arrayCacheF32 = []; - var arrayCacheI32 = []; + if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && + gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { - // Float32Array caches used for uploading Matrix uniforms + return 'mediump'; - var mat4array = new Float32Array( 16 ); - var mat3array = new Float32Array( 9 ); - var mat2array = new Float32Array( 4 ); + } - // Flattening for arrays of vectors and matrices + } - function flatten( array, nBlocks, blockSize ) { + return 'lowp'; - var firstElem = array[ 0 ]; + } - if ( firstElem <= 0 || firstElem > 0 ) return array; - // unoptimized: ! isNaN( firstElem ) - // see http://jacksondunstan.com/articles/983 + /* eslint-disable no-undef */ + var isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) || + ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext ); + /* eslint-enable no-undef */ - var n = nBlocks * blockSize, - r = arrayCacheF32[ n ]; + var precision = parameters.precision !== undefined ? parameters.precision : 'highp'; + var maxPrecision = getMaxPrecision( precision ); - if ( r === undefined ) { + if ( maxPrecision !== precision ) { - r = new Float32Array( n ); - arrayCacheF32[ n ] = r; + console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); + precision = maxPrecision; } - if ( nBlocks !== 0 ) { + var logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; - firstElem.toArray( r, 0 ); + var maxTextures = gl.getParameter( 34930 ); + var maxVertexTextures = gl.getParameter( 35660 ); + var maxTextureSize = gl.getParameter( 3379 ); + var maxCubemapSize = gl.getParameter( 34076 ); - for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) { + var maxAttributes = gl.getParameter( 34921 ); + var maxVertexUniforms = gl.getParameter( 36347 ); + var maxVaryings = gl.getParameter( 36348 ); + var maxFragmentUniforms = gl.getParameter( 36349 ); - offset += blockSize; - array[ i ].toArray( r, offset ); + var vertexTextures = maxVertexTextures > 0; + var floatFragmentTextures = isWebGL2 || !! extensions.get( 'OES_texture_float' ); + var floatVertexTextures = vertexTextures && floatFragmentTextures; - } + var maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0; - } + return { - return r; + isWebGL2: isWebGL2, - } + getMaxAnisotropy: getMaxAnisotropy, + getMaxPrecision: getMaxPrecision, - function arraysEqual( a, b ) { + precision: precision, + logarithmicDepthBuffer: logarithmicDepthBuffer, - if ( a.length !== b.length ) return false; + maxTextures: maxTextures, + maxVertexTextures: maxVertexTextures, + maxTextureSize: maxTextureSize, + maxCubemapSize: maxCubemapSize, - for ( var i = 0, l = a.length; i < l; i ++ ) { + maxAttributes: maxAttributes, + maxVertexUniforms: maxVertexUniforms, + maxVaryings: maxVaryings, + maxFragmentUniforms: maxFragmentUniforms, - if ( a[ i ] !== b[ i ] ) return false; + vertexTextures: vertexTextures, + floatFragmentTextures: floatFragmentTextures, + floatVertexTextures: floatVertexTextures, - } + maxSamples: maxSamples - return true; + }; } - function copyArray( a, b ) { + function WebGLClipping() { - for ( var i = 0, l = b.length; i < l; i ++ ) { + var scope = this; - a[ i ] = b[ i ]; + var globalState = null, + numGlobalPlanes = 0, + localClippingEnabled = false, + renderingShadows = false; - } + var plane = new Plane(), + viewNormalMatrix = new Matrix3(), - } + uniform = { value: null, needsUpdate: false }; - // Texture unit allocation + this.uniform = uniform; + this.numPlanes = 0; + this.numIntersection = 0; - function allocTexUnits( renderer, n ) { + this.init = function ( planes, enableLocalClipping, camera ) { - var r = arrayCacheI32[ n ]; + var 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; - if ( r === undefined ) { + localClippingEnabled = enableLocalClipping; - r = new Int32Array( n ); - arrayCacheI32[ n ] = r; + globalState = projectPlanes( planes, camera, 0 ); + numGlobalPlanes = planes.length; - } + return enabled; - for ( var i = 0; i !== n; ++ i ) - r[ i ] = renderer.allocTextureUnit(); + }; - return r; + this.beginShadows = function () { - } + renderingShadows = true; + projectPlanes( null ); - // --- Setters --- + }; - // Note: Defining these methods externally, because they come in a bunch - // and this way their names minify. + this.endShadows = function () { - // Single scalar + renderingShadows = false; + resetGlobalState(); - function setValue1f( gl, v ) { + }; - var cache = this.cache; + this.setState = function ( planes, clipIntersection, clipShadows, camera, cache, fromCache ) { - if ( cache[ 0 ] === v ) return; + if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { - gl.uniform1f( this.addr, v ); + // there's no local clipping - cache[ 0 ] = v; + if ( renderingShadows ) { - } + // there's no global clipping - function setValue1i( gl, v ) { + projectPlanes( null ); - var cache = this.cache; + } else { - if ( cache[ 0 ] === v ) return; + resetGlobalState(); - gl.uniform1i( this.addr, v ); + } - cache[ 0 ] = v; + } else { - } + var nGlobal = renderingShadows ? 0 : numGlobalPlanes, + lGlobal = nGlobal * 4; - // Single float vector (from flat array or THREE.VectorN) + var dstArray = cache.clippingState || null; - function setValue2fv( gl, v ) { + uniform.value = dstArray; // ensure unique state - var cache = this.cache; + dstArray = projectPlanes( planes, camera, lGlobal, fromCache ); - if ( v.x !== undefined ) { + for ( var i = 0; i !== lGlobal; ++ i ) { - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { + dstArray[ i ] = globalState[ i ]; - gl.uniform2f( this.addr, v.x, v.y ); + } - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; + cache.clippingState = dstArray; + this.numIntersection = clipIntersection ? this.numPlanes : 0; + this.numPlanes += nGlobal; } - } else { - if ( arraysEqual( cache, v ) ) return; + }; - gl.uniform2fv( this.addr, v ); + function resetGlobalState() { - copyArray( cache, v ); + if ( uniform.value !== globalState ) { - } + uniform.value = globalState; + uniform.needsUpdate = numGlobalPlanes > 0; - } + } - function setValue3fv( gl, v ) { + scope.numPlanes = numGlobalPlanes; + scope.numIntersection = 0; - var cache = this.cache; + } - if ( v.x !== undefined ) { + function projectPlanes( planes, camera, dstOffset, skipTransform ) { - if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { + var nPlanes = planes !== null ? planes.length : 0, + dstArray = null; - gl.uniform3f( this.addr, v.x, v.y, v.z ); + if ( nPlanes !== 0 ) { - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; + dstArray = uniform.value; - } + if ( skipTransform !== true || dstArray === null ) { - } else if ( v.r !== undefined ) { + var flatSize = dstOffset + nPlanes * 4, + viewMatrix = camera.matrixWorldInverse; - if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { + viewNormalMatrix.getNormalMatrix( viewMatrix ); - gl.uniform3f( this.addr, v.r, v.g, v.b ); + if ( dstArray === null || dstArray.length < flatSize ) { - cache[ 0 ] = v.r; - cache[ 1 ] = v.g; - cache[ 2 ] = v.b; + dstArray = new Float32Array( flatSize ); - } + } - } else { - - if ( arraysEqual( cache, v ) ) return; - - gl.uniform3fv( this.addr, v ); - - copyArray( cache, v ); + for ( var 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; - function setValue4fv( gl, v ) { + } - var cache = this.cache; + } - if ( v.x !== undefined ) { + uniform.value = dstArray; + uniform.needsUpdate = true; - 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 ); + scope.numPlanes = nPlanes; + scope.numIntersection = 0; - cache[ 0 ] = v.x; - cache[ 1 ] = v.y; - cache[ 2 ] = v.z; - cache[ 3 ] = v.w; + return dstArray; - } + } - } else { + } - if ( arraysEqual( cache, v ) ) return; + function WebGLExtensions( gl ) { - gl.uniform4fv( this.addr, v ); + var extensions = {}; - copyArray( cache, v ); + return { - } + has: function ( name ) { - } + if ( extensions[ name ] !== undefined ) { - // Single matrix (from flat array or MatrixN) + return extensions[ name ]; - function setValue2fm( gl, v ) { + } - var cache = this.cache; - var elements = v.elements; + var extension; - if ( elements === undefined ) { + switch ( name ) { - if ( arraysEqual( cache, v ) ) return; + case 'WEBGL_depth_texture': + extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); + break; - gl.uniformMatrix2fv( this.addr, false, v ); + 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; - copyArray( cache, v ); + 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; - } else { + case 'WEBGL_compressed_texture_pvrtc': + extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); + break; - if ( arraysEqual( cache, elements ) ) return; + default: + extension = gl.getExtension( name ); - mat2array.set( elements ); + } - gl.uniformMatrix2fv( this.addr, false, mat2array ); + extensions[ name ] = extension; - copyArray( cache, elements ); + return !! extension; - } + }, - } + get: function ( name ) { - function setValue3fm( gl, v ) { + if ( ! this.has( name ) ) { - var cache = this.cache; - var elements = v.elements; + console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); - if ( elements === undefined ) { + } - if ( arraysEqual( cache, v ) ) return; + return extensions[ name ]; - gl.uniformMatrix3fv( this.addr, false, v ); + } - copyArray( cache, v ); + }; - } else { + } - if ( arraysEqual( cache, elements ) ) return; + function WebGLGeometries( gl, attributes, info, bindingStates ) { - mat3array.set( elements ); + var geometries = new WeakMap(); + var wireframeAttributes = new WeakMap(); - gl.uniformMatrix3fv( this.addr, false, mat3array ); + function onGeometryDispose( event ) { - copyArray( cache, elements ); + var geometry = event.target; + var buffergeometry = geometries.get( geometry ); - } + if ( buffergeometry.index !== null ) { - } + attributes.remove( buffergeometry.index ); - function setValue4fm( gl, v ) { + } - var cache = this.cache; - var elements = v.elements; + for ( var name in buffergeometry.attributes ) { - if ( elements === undefined ) { + attributes.remove( buffergeometry.attributes[ name ] ); - if ( arraysEqual( cache, v ) ) return; + } - gl.uniformMatrix4fv( this.addr, false, v ); + geometry.removeEventListener( 'dispose', onGeometryDispose ); - copyArray( cache, v ); + geometries.delete( geometry ); - } else { + var attribute = wireframeAttributes.get( buffergeometry ); - if ( arraysEqual( cache, elements ) ) return; + if ( attribute ) { - mat4array.set( elements ); + attributes.remove( attribute ); + wireframeAttributes.delete( buffergeometry ); - gl.uniformMatrix4fv( this.addr, false, mat4array ); + } - copyArray( cache, elements ); + bindingStates.releaseStatesOfGeometry( geometry ); - } + if ( geometry.isInstancedBufferGeometry === true ) { - } + delete geometry._maxInstanceCount; - // Single texture (2D / Cube) + } - function setValueT1( gl, v, renderer ) { + // - var cache = this.cache; - var unit = renderer.allocTextureUnit(); + info.memory.geometries --; - if ( cache[ 0 ] !== unit ) { + } - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; + function get( object, geometry ) { - } + var buffergeometry = geometries.get( geometry ); - renderer.setTexture2D( v || emptyTexture, unit ); + if ( buffergeometry ) { return buffergeometry; } - } + geometry.addEventListener( 'dispose', onGeometryDispose ); - function setValueT3D1( gl, v, renderer ) { + if ( geometry.isBufferGeometry ) { - var cache = this.cache; - var unit = renderer.allocTextureUnit(); + buffergeometry = geometry; - if ( cache[ 0 ] !== unit ) { + } else if ( geometry.isGeometry ) { - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; + if ( geometry._bufferGeometry === undefined ) { - } + geometry._bufferGeometry = new BufferGeometry().setFromObject( object ); - renderer.setTexture3D( v || emptyTexture3d, unit ); + } - } + buffergeometry = geometry._bufferGeometry; - function setValueT6( gl, v, renderer ) { + } - var cache = this.cache; - var unit = renderer.allocTextureUnit(); + geometries.set( geometry, buffergeometry ); - if ( cache[ 0 ] !== unit ) { + info.memory.geometries ++; - gl.uniform1i( this.addr, unit ); - cache[ 0 ] = unit; + return buffergeometry; } - renderer.setTextureCube( v || emptyCubeTexture, unit ); + function update( geometry ) { - } + var geometryAttributes = geometry.attributes; - // Integer / Boolean vectors or arrays thereof (always flat arrays) + // Updating index buffer in VAO now. See WebGLBindingStates. - function setValue2iv( gl, v ) { + for ( var name in geometryAttributes ) { - var cache = this.cache; + attributes.update( geometryAttributes[ name ], 34962 ); - if ( arraysEqual( cache, v ) ) return; + } - gl.uniform2iv( this.addr, v ); + // morph targets - copyArray( cache, v ); + var morphAttributes = geometry.morphAttributes; - } + for ( var name$1 in morphAttributes ) { - function setValue3iv( gl, v ) { + var array = morphAttributes[ name$1 ]; - var cache = this.cache; + for ( var i = 0, l = array.length; i < l; i ++ ) { - if ( arraysEqual( cache, v ) ) return; + attributes.update( array[ i ], 34962 ); - gl.uniform3iv( this.addr, v ); + } - copyArray( cache, v ); + } - } + } - function setValue4iv( gl, v ) { + function updateWireframeAttribute( geometry ) { - var cache = this.cache; + var indices = []; - if ( arraysEqual( cache, v ) ) return; + var geometryIndex = geometry.index; + var geometryPosition = geometry.attributes.position; + var version = 0; - gl.uniform4iv( this.addr, v ); + if ( geometryIndex !== null ) { - copyArray( cache, v ); + var array = geometryIndex.array; + version = geometryIndex.version; - } + for ( var i = 0, l = array.length; i < l; i += 3 ) { - // Helper to pick the right setter for the singular case + var a = array[ i + 0 ]; + var b = array[ i + 1 ]; + var c = array[ i + 2 ]; - function getSingularSetter( type ) { + indices.push( a, b, b, c, c, a ); - switch ( type ) { + } - case 0x1406: return setValue1f; // FLOAT - case 0x8b50: return setValue2fv; // _VEC2 - case 0x8b51: return setValue3fv; // _VEC3 - case 0x8b52: return setValue4fv; // _VEC4 + } else { - case 0x8b5a: return setValue2fm; // _MAT2 - case 0x8b5b: return setValue3fm; // _MAT3 - case 0x8b5c: return setValue4fm; // _MAT4 + var array$1 = geometryPosition.array; + version = geometryPosition.version; - case 0x8b5e: case 0x8d66: return setValueT1; // SAMPLER_2D, SAMPLER_EXTERNAL_OES - case 0x8B5F: return setValueT3D1; // SAMPLER_3D - case 0x8b60: return setValueT6; // SAMPLER_CUBE + for ( var i$1 = 0, l$1 = ( array$1.length / 3 ) - 1; i$1 < l$1; i$1 += 3 ) { - case 0x1404: case 0x8b56: return setValue1i; // INT, BOOL - case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2 - case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3 - case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4 + var a$1 = i$1 + 0; + var b$1 = i$1 + 1; + var c$1 = i$1 + 2; - } + indices.push( a$1, b$1, b$1, c$1, c$1, a$1 ); - } + } - // Array of scalars + } - function setValue1fv( gl, v ) { + var attribute = new ( arrayMax( indices ) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); + attribute.version = version; - var cache = this.cache; + // Updating index buffer in VAO now. See WebGLBindingStates - if ( arraysEqual( cache, v ) ) return; + // - gl.uniform1fv( this.addr, v ); + var previousAttribute = wireframeAttributes.get( geometry ); - copyArray( cache, v ); + if ( previousAttribute ) { attributes.remove( previousAttribute ); } - } - function setValue1iv( gl, v ) { + // - var cache = this.cache; + wireframeAttributes.set( geometry, attribute ); - if ( arraysEqual( cache, v ) ) return; + } - gl.uniform1iv( this.addr, v ); + function getWireframeAttribute( geometry ) { - copyArray( cache, v ); + var currentAttribute = wireframeAttributes.get( geometry ); - } + if ( currentAttribute ) { - // Array of vectors (flat or from THREE classes) + var geometryIndex = geometry.index; - function setValueV2a( gl, v ) { + if ( geometryIndex !== null ) { - var cache = this.cache; - var data = flatten( v, this.size, 2 ); + // if the attribute is obsolete, create a new one - if ( arraysEqual( cache, data ) ) return; + if ( currentAttribute.version < geometryIndex.version ) { - gl.uniform2fv( this.addr, data ); + updateWireframeAttribute( geometry ); - this.updateCache( data ); + } - } + } - function setValueV3a( gl, v ) { + } else { - var cache = this.cache; - var data = flatten( v, this.size, 3 ); + updateWireframeAttribute( geometry ); - if ( arraysEqual( cache, data ) ) return; + } - gl.uniform3fv( this.addr, data ); + return wireframeAttributes.get( geometry ); - this.updateCache( data ); + } - } + return { - function setValueV4a( gl, v ) { + get: get, + update: update, - var cache = this.cache; - var data = flatten( v, this.size, 4 ); + getWireframeAttribute: getWireframeAttribute - if ( arraysEqual( cache, data ) ) return; + }; - gl.uniform4fv( this.addr, data ); + } - this.updateCache( data ); + function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { - } + var isWebGL2 = capabilities.isWebGL2; - // Array of matrices (flat or from THREE clases) + var mode; - function setValueM2a( gl, v ) { + function setMode( value ) { - var cache = this.cache; - var data = flatten( v, this.size, 4 ); + mode = value; - if ( arraysEqual( cache, data ) ) return; + } - gl.uniformMatrix2fv( this.addr, false, data ); + var type, bytesPerElement; - this.updateCache( data ); + function setIndex( value ) { - } + type = value.type; + bytesPerElement = value.bytesPerElement; - function setValueM3a( gl, v ) { + } - var cache = this.cache; - var data = flatten( v, this.size, 9 ); + function render( start, count ) { - if ( arraysEqual( cache, data ) ) return; + gl.drawElements( mode, count, type, start * bytesPerElement ); - gl.uniformMatrix3fv( this.addr, false, data ); + info.update( count, mode, 1 ); - this.updateCache( data ); + } - } + function renderInstances( start, count, primcount ) { - function setValueM4a( gl, v ) { + if ( primcount === 0 ) { return; } - var cache = this.cache; - var data = flatten( v, this.size, 16 ); + var extension, methodName; - if ( arraysEqual( cache, data ) ) return; + if ( isWebGL2 ) { - gl.uniformMatrix4fv( this.addr, false, data ); + extension = gl; + methodName = 'drawElementsInstanced'; - this.updateCache( data ); + } else { - } + extension = extensions.get( 'ANGLE_instanced_arrays' ); + methodName = 'drawElementsInstancedANGLE'; - // Array of textures (2D / Cube) + if ( extension === null ) { - function setValueT1a( gl, v, renderer ) { + console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; - var cache = this.cache; - var n = v.length; + } - var units = allocTexUnits( renderer, n ); + } - if ( arraysEqual( cache, units ) === false ) { + extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); - gl.uniform1iv( this.addr, units ); - copyArray( cache, units ); + info.update( count, mode, primcount ); } - for ( var i = 0; i !== n; ++ i ) { - - renderer.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); + // - } + this.setMode = setMode; + this.setIndex = setIndex; + this.render = render; + this.renderInstances = renderInstances; } - function setValueT6a( gl, v, renderer ) { - - var cache = this.cache; - var n = v.length; + function WebGLInfo( gl ) { - var units = allocTexUnits( renderer, n ); + var memory = { + geometries: 0, + textures: 0 + }; - if ( arraysEqual( cache, units ) === false ) { + var render = { + frame: 0, + calls: 0, + triangles: 0, + points: 0, + lines: 0 + }; - gl.uniform1iv( this.addr, units ); - copyArray( cache, units ); + function update( count, mode, instanceCount ) { - } + render.calls ++; - for ( var i = 0; i !== n; ++ i ) { + switch ( mode ) { - renderer.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); + case 4: + render.triangles += instanceCount * ( count / 3 ); + break; - } + case 1: + render.lines += instanceCount * ( count / 2 ); + break; - } + case 3: + render.lines += instanceCount * ( count - 1 ); + break; - // Helper to pick the right setter for a pure (bottom-level) array + case 2: + render.lines += instanceCount * count; + break; - function getPureArraySetter( type ) { + case 0: + render.points += instanceCount * count; + break; - switch ( type ) { + default: + console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode ); + break; - case 0x1406: return setValue1fv; // FLOAT - case 0x8b50: return setValueV2a; // _VEC2 - case 0x8b51: return setValueV3a; // _VEC3 - case 0x8b52: return setValueV4a; // _VEC4 + } - case 0x8b5a: return setValueM2a; // _MAT2 - case 0x8b5b: return setValueM3a; // _MAT3 - case 0x8b5c: return setValueM4a; // _MAT4 + } - case 0x8b5e: return setValueT1a; // SAMPLER_2D - case 0x8b60: return setValueT6a; // SAMPLER_CUBE + function reset() { - case 0x1404: case 0x8b56: return setValue1iv; // INT, BOOL - case 0x8b53: case 0x8b57: return setValue2iv; // _VEC2 - case 0x8b54: case 0x8b58: return setValue3iv; // _VEC3 - case 0x8b55: case 0x8b59: return setValue4iv; // _VEC4 + 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 + }; + } - // --- Uniform Classes --- + function numericalSort( a, b ) { - function SingleUniform( id, activeInfo, addr ) { + return a[ 0 ] - b[ 0 ]; - this.id = id; - this.addr = addr; - this.cache = []; - this.setValue = getSingularSetter( activeInfo.type ); + } - // this.path = activeInfo.name; // DEBUG + function absNumericalSort( a, b ) { + + return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); } - function PureArrayUniform( id, activeInfo, addr ) { + function WebGLMorphtargets( gl ) { - this.id = id; - this.addr = addr; - this.cache = []; - this.size = activeInfo.size; - this.setValue = getPureArraySetter( activeInfo.type ); + var influencesList = {}; + var morphInfluences = new Float32Array( 8 ); - // this.path = activeInfo.name; // DEBUG + var workInfluences = []; - } + for ( var i = 0; i < 8; i ++ ) { - PureArrayUniform.prototype.updateCache = function ( data ) { + workInfluences[ i ] = [ i, 0 ]; - var cache = this.cache; + } - if ( data instanceof Float32Array && cache.length !== data.length ) { + function update( object, geometry, material, program ) { - this.cache = new Float32Array( data.length ); + var 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 - copyArray( cache, data ); + var length = objectInfluences === undefined ? 0 : objectInfluences.length; - }; + var influences = influencesList[ geometry.id ]; - function StructuredUniform( id ) { + if ( influences === undefined ) { - this.id = id; + // initialise list - UniformContainer.call( this ); // mix-in + influences = []; - } + for ( var i = 0; i < length; i ++ ) { - StructuredUniform.prototype.setValue = function ( gl, value, renderer ) { + influences[ i ] = [ i, 0 ]; - var seq = this.seq; + } - for ( var i = 0, n = seq.length; i !== n; ++ i ) { + influencesList[ geometry.id ] = influences; - var u = seq[ i ]; - u.setValue( gl, value[ u.id ], renderer ); + } - } + // Collect influences - }; + for ( var i$1 = 0; i$1 < length; i$1 ++ ) { - // --- Top-level --- + var influence = influences[ i$1 ]; - // Parser - builds up the property tree from the path strings + influence[ 0 ] = i$1; + influence[ 1 ] = objectInfluences[ i$1 ]; - var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/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. + influences.sort( absNumericalSort ); - function addUniform( container, uniformObject ) { + for ( var i$2 = 0; i$2 < 8; i$2 ++ ) { - container.seq.push( uniformObject ); - container.map[ uniformObject.id ] = uniformObject; + if ( i$2 < length && influences[ i$2 ][ 1 ] ) { - } + workInfluences[ i$2 ][ 0 ] = influences[ i$2 ][ 0 ]; + workInfluences[ i$2 ][ 1 ] = influences[ i$2 ][ 1 ]; - function parseUniform( activeInfo, addr, container ) { + } else { - var path = activeInfo.name, - pathLength = path.length; + workInfluences[ i$2 ][ 0 ] = Number.MAX_SAFE_INTEGER; + workInfluences[ i$2 ][ 1 ] = 0; - // reset RegExp object, because of the early exit of a previous run - RePathPart.lastIndex = 0; + } - while ( true ) { + } - var match = RePathPart.exec( path ), - matchEnd = RePathPart.lastIndex, + workInfluences.sort( numericalSort ); - id = match[ 1 ], - idIsIndex = match[ 2 ] === ']', - subscript = match[ 3 ]; + var morphTargets = material.morphTargets && geometry.morphAttributes.position; + var morphNormals = material.morphNormals && geometry.morphAttributes.normal; - if ( idIsIndex ) id = id | 0; // convert to integer + var morphInfluencesSum = 0; - if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { + for ( var i$3 = 0; i$3 < 8; i$3 ++ ) { - // bare name or "pure" bottom-level array "[0]" suffix + var influence$1 = workInfluences[ i$3 ]; + var index = influence$1[ 0 ]; + var value = influence$1[ 1 ]; - addUniform( container, subscript === undefined ? - new SingleUniform( id, activeInfo, addr ) : - new PureArrayUniform( id, activeInfo, addr ) ); + if ( index !== Number.MAX_SAFE_INTEGER && value ) { - break; + if ( morphTargets && geometry.getAttribute( 'morphTarget' + i$3 ) !== morphTargets[ index ] ) { - } else { + geometry.setAttribute( 'morphTarget' + i$3, morphTargets[ index ] ); - // step into inner node / create it in case it doesn't exist + } - var map = container.map, next = map[ id ]; + if ( morphNormals && geometry.getAttribute( 'morphNormal' + i$3 ) !== morphNormals[ index ] ) { - if ( next === undefined ) { + geometry.setAttribute( 'morphNormal' + i$3, morphNormals[ index ] ); - next = new StructuredUniform( id ); - addUniform( container, next ); + } - } + morphInfluences[ i$3 ] = value; + morphInfluencesSum += value; - container = next; + } else { - } + if ( morphTargets && geometry.getAttribute( 'morphTarget' + i$3 ) !== undefined ) { - } + geometry.deleteAttribute( 'morphTarget' + i$3 ); - } + } - // Root Container + if ( morphNormals && geometry.getAttribute( 'morphNormal' + i$3 ) !== undefined ) { - function WebGLUniforms( gl, program, renderer ) { + geometry.deleteAttribute( 'morphNormal' + i$3 ); - UniformContainer.call( this ); + } - this.renderer = renderer; + morphInfluences[ i$3 ] = 0; - var n = gl.getProgramParameter( program, 35718 ); + } - for ( var i = 0; i < n; ++ i ) { + } - var info = gl.getActiveUniform( program, i ), - addr = gl.getUniformLocation( program, info.name ); + // 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) + var morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; - parseUniform( info, addr, this ); + program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); + program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); } - } + return { - WebGLUniforms.prototype.setValue = function ( gl, name, value ) { + update: update - var u = this.map[ name ]; + }; - if ( u !== undefined ) u.setValue( gl, value, this.renderer ); + } - }; + function WebGLObjects( gl, geometries, attributes, info ) { - WebGLUniforms.prototype.setOptional = function ( gl, object, name ) { + var updateMap = new WeakMap(); - var v = object[ name ]; + function update( object ) { - if ( v !== undefined ) this.setValue( gl, name, v ); + var frame = info.render.frame; - }; + var geometry = object.geometry; + var buffergeometry = geometries.get( object, geometry ); + // Update once per frame - // Static interface + if ( updateMap.get( buffergeometry ) !== frame ) { - WebGLUniforms.upload = function ( gl, seq, values, renderer ) { + if ( geometry.isGeometry ) { - for ( var i = 0, n = seq.length; i !== n; ++ i ) { + buffergeometry.updateFromObject( object ); - var u = seq[ i ], - v = values[ u.id ]; + } - if ( v.needsUpdate !== false ) { + geometries.update( buffergeometry ); - // note: always updating when .needsUpdate is undefined - u.setValue( gl, v.value, renderer ); + updateMap.set( buffergeometry, frame ); } - } + if ( object.isInstancedMesh ) { - }; + attributes.update( object.instanceMatrix, 34962 ); - WebGLUniforms.seqWithValue = function ( seq, values ) { + } - var r = []; + return buffergeometry; - for ( var i = 0, n = seq.length; i !== n; ++ i ) { + } - var u = seq[ i ]; - if ( u.id in values ) r.push( u ); + function dispose() { - } + updateMap = new WeakMap(); - return r; + } - }; + return { - /** - * @author mrdoob / http://mrdoob.com/ - */ + update: update, + dispose: dispose - function addLineNumbers( string ) { + }; - var lines = string.split( '\n' ); + } - for ( var i = 0; i < lines.length; i ++ ) { + function CubeTexture( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { - lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; + images = images !== undefined ? images : []; + mapping = mapping !== undefined ? mapping : CubeReflectionMapping; + format = format !== undefined ? format : RGBFormat; - } + Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - return lines.join( '\n' ); + this.flipY = false; } - function WebGLShader( gl, type, string ) { + CubeTexture.prototype = Object.create( Texture.prototype ); + CubeTexture.prototype.constructor = CubeTexture; - var shader = gl.createShader( type ); + CubeTexture.prototype.isCubeTexture = true; - gl.shaderSource( shader, string ); - gl.compileShader( shader ); + Object.defineProperty( CubeTexture.prototype, 'images', { - if ( gl.getShaderParameter( shader, 35713 ) === false ) { + get: function () { - console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' ); + return this.image; - } + }, - if ( gl.getShaderInfoLog( shader ) !== '' ) { + set: function ( value ) { - console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', type === 35633 ? 'vertex' : 'fragment', gl.getShaderInfoLog( shader ), addLineNumbers( string ) ); + this.image = value; } - // --enable-privileged-webgl-extension - // console.log( type, gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); + } ); - return shader; + function DataTexture2DArray( data, width, height, depth ) { + + Texture.call( this, null ); + + this.image = { data: data || null, width: width || 1, height: height || 1, depth: depth || 1 }; + + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; + + this.wrapR = ClampToEdgeWrapping; + + this.generateMipmaps = false; + this.flipY = false; + + this.needsUpdate = true; } - /** - * @author mrdoob / http://mrdoob.com/ - */ + DataTexture2DArray.prototype = Object.create( Texture.prototype ); + DataTexture2DArray.prototype.constructor = DataTexture2DArray; + DataTexture2DArray.prototype.isDataTexture2DArray = true; - var programIdCount = 0; + function DataTexture3D( data, width, height, depth ) { - function getEncodingComponents( encoding ) { + // 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 - switch ( encoding ) { + Texture.call( this, null ); - 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 ) )' ]; - default: - throw new Error( 'unsupported encoding: ' + encoding ); + this.image = { data: data || null, width: width || 1, height: height || 1, depth: depth || 1 }; - } + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - } + this.wrapR = ClampToEdgeWrapping; - function getTexelDecodingFunction( functionName, encoding ) { + this.generateMipmaps = false; + this.flipY = false; + + this.needsUpdate = true; - var components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }'; } - function getTexelEncodingFunction( functionName, encoding ) { + DataTexture3D.prototype = Object.create( Texture.prototype ); + DataTexture3D.prototype.constructor = DataTexture3D; + DataTexture3D.prototype.isDataTexture3D = true; - var components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; + /** + * 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 + * + */ - } + var emptyTexture = new Texture(); + var emptyTexture2dArray = new DataTexture2DArray(); + var emptyTexture3d = new DataTexture3D(); + var emptyCubeTexture = new CubeTexture(); - function getToneMappingFunction( functionName, toneMapping ) { + // --- Utilities --- - var toneMappingName; + // Array Caches (provide typed arrays for temporary by size) - switch ( toneMapping ) { + var arrayCacheF32 = []; + var arrayCacheI32 = []; - case LinearToneMapping: - toneMappingName = 'Linear'; - break; + // Float32Array caches used for uploading Matrix uniforms - case ReinhardToneMapping: - toneMappingName = 'Reinhard'; - break; + var mat4array = new Float32Array( 16 ); + var mat3array = new Float32Array( 9 ); + var mat2array = new Float32Array( 4 ); - case Uncharted2ToneMapping: - toneMappingName = 'Uncharted2'; - break; + // Flattening for arrays of vectors and matrices - case CineonToneMapping: - toneMappingName = 'OptimizedCineon'; - break; + function flatten( array, nBlocks, blockSize ) { - default: - throw new Error( 'unsupported toneMapping: ' + toneMapping ); + var firstElem = array[ 0 ]; + + if ( firstElem <= 0 || firstElem > 0 ) { return array; } + // unoptimized: ! isNaN( firstElem ) + // see http://jacksondunstan.com/articles/983 + + var n = nBlocks * blockSize, + r = arrayCacheF32[ n ]; + + if ( r === undefined ) { + + r = new Float32Array( n ); + arrayCacheF32[ n ] = r; } - return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; + if ( nBlocks !== 0 ) { - } + firstElem.toArray( r, 0 ); + + for ( var i = 1, offset = 0; i !== nBlocks; ++ i ) { - function generateExtensions( extensions, parameters, rendererExtensions ) { + offset += blockSize; + array[ i ].toArray( r, offset ); - extensions = extensions || {}; + } - var chunks = [ - ( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || ( parameters.normalMap && ! parameters.objectSpaceNormalMap ) || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '', - ( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '', - ( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '', - ( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : '' - ]; + } - return chunks.filter( filterEmptyLine ).join( '\n' ); + return r; } - function generateDefines( defines ) { + function arraysEqual( a, b ) { - var chunks = []; + if ( a.length !== b.length ) { return false; } - for ( var name in defines ) { + for ( var i = 0, l = a.length; i < l; i ++ ) { - var value = defines[ name ]; + if ( a[ i ] !== b[ i ] ) { return false; } - if ( value === false ) continue; + } - chunks.push( '#define ' + name + ' ' + value ); + return true; - } + } - return chunks.join( '\n' ); + function copyArray( a, b ) { + + for ( var i = 0, l = b.length; i < l; i ++ ) { + + a[ i ] = b[ i ]; + + } } - function fetchAttributeLocations( gl, program ) { + // Texture unit allocation - var attributes = {}; + function allocTexUnits( textures, n ) { - var n = gl.getProgramParameter( program, 35721 ); + var r = arrayCacheI32[ n ]; - for ( var i = 0; i < n; i ++ ) { + if ( r === undefined ) { - var info = gl.getActiveAttrib( program, i ); - var name = info.name; + r = new Int32Array( n ); + arrayCacheI32[ n ] = r; - // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); + } - attributes[ name ] = gl.getAttribLocation( program, name ); + for ( var i = 0; i !== n; ++ i ) { + + r[ i ] = textures.allocateTextureUnit(); } - return attributes; + return r; } - function filterEmptyLine( string ) { + // --- Setters --- - return string !== ''; + // Note: Defining these methods externally, because they come in a bunch + // and this way their names minify. - } + // Single scalar - function replaceLightNums( string, parameters ) { + function setValueV1f( gl, v ) { - 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 ); + var cache = this.cache; - } + if ( cache[ 0 ] === v ) { return; } - function replaceClippingPlaneNums( string, parameters ) { + gl.uniform1f( this.addr, v ); - return string - .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) - .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); + cache[ 0 ] = v; } - function parseIncludes( string ) { + // Single float vector (from flat array or THREE.VectorN) + + function setValueV2f( gl, v ) { - var pattern = /^[ \t]*#include +<([\w\d./]+)>/gm; + var cache = this.cache; - function replace( match, include ) { + if ( v.x !== undefined ) { - var replace = ShaderChunk[ include ]; + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { - if ( replace === undefined ) { + gl.uniform2f( this.addr, v.x, v.y ); - throw new Error( 'Can not resolve #include <' + include + '>' ); + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; } - return parseIncludes( replace ); + } else { + + if ( arraysEqual( cache, v ) ) { return; } - } + gl.uniform2fv( this.addr, v ); + + copyArray( cache, v ); - return string.replace( pattern, replace ); + } } - function unrollLoops( string ) { + function setValueV3f( gl, v ) { - var pattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g; + var cache = this.cache; - function replace( match, start, end, snippet ) { + if ( v.x !== undefined ) { - var unroll = ''; + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { - for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) { + gl.uniform3f( this.addr, v.x, v.y, v.z ); - unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' ); + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; + cache[ 2 ] = v.z; } - return unroll; + } else if ( v.r !== undefined ) { - } + if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { - return string.replace( pattern, replace ); + gl.uniform3f( this.addr, v.r, v.g, v.b ); - } + cache[ 0 ] = v.r; + cache[ 1 ] = v.g; + cache[ 2 ] = v.b; - function WebGLProgram( renderer, extensions, code, material, shader, parameters, capabilities ) { + } - var gl = renderer.context; + } else { - var defines = material.defines; + if ( arraysEqual( cache, v ) ) { return; } - var vertexShader = shader.vertexShader; - var fragmentShader = shader.fragmentShader; + gl.uniform3fv( this.addr, v ); - var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; + copyArray( cache, v ); - if ( parameters.shadowMapType === PCFShadowMap ) { + } - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; + } - } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { + function setValueV4f( gl, v ) { - shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; + var cache = this.cache; - } + if ( v.x !== undefined ) { - var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; - var envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { - if ( parameters.envMap ) { + gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); - switch ( material.envMap.mapping ) { + cache[ 0 ] = v.x; + cache[ 1 ] = v.y; + cache[ 2 ] = v.z; + cache[ 3 ] = v.w; - case CubeReflectionMapping: - case CubeRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - break; + } - case CubeUVReflectionMapping: - case CubeUVRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; - break; + } else { - case EquirectangularReflectionMapping: - case EquirectangularRefractionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; - break; + if ( arraysEqual( cache, v ) ) { return; } - case SphericalReflectionMapping: - envMapTypeDefine = 'ENVMAP_TYPE_SPHERE'; - break; + gl.uniform4fv( this.addr, v ); - } + copyArray( cache, v ); - switch ( material.envMap.mapping ) { + } - case CubeRefractionMapping: - case EquirectangularRefractionMapping: - envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; - break; + } - } + // Single matrix (from flat array or MatrixN) - switch ( material.combine ) { + function setValueM2( gl, v ) { - case MultiplyOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; - break; + var cache = this.cache; + var elements = v.elements; - case MixOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; - break; + if ( elements === undefined ) { - case AddOperation: - envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; - break; + if ( arraysEqual( cache, v ) ) { return; } - } + gl.uniformMatrix2fv( this.addr, false, v ); - } + copyArray( cache, v ); - var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; + } else { - // console.log( 'building new program ' ); + if ( arraysEqual( cache, elements ) ) { return; } - // + mat2array.set( elements ); - var customExtensions = capabilities.isWebGL2 ? '' : generateExtensions( material.extensions, parameters, extensions ); + gl.uniformMatrix2fv( this.addr, false, mat2array ); - var customDefines = generateDefines( defines ); + copyArray( cache, elements ); - // + } - var program = gl.createProgram(); + } - var prefixVertex, prefixFragment; + function setValueM3( gl, v ) { - if ( material.isRawShaderMaterial ) { + var cache = this.cache; + var elements = v.elements; - prefixVertex = [ + if ( elements === undefined ) { - customDefines + if ( arraysEqual( cache, v ) ) { return; } - ].filter( filterEmptyLine ).join( '\n' ); + gl.uniformMatrix3fv( this.addr, false, v ); - if ( prefixVertex.length > 0 ) { + copyArray( cache, v ); - prefixVertex += '\n'; + } else { - } + if ( arraysEqual( cache, elements ) ) { return; } - prefixFragment = [ + mat3array.set( elements ); - customExtensions, - customDefines + gl.uniformMatrix3fv( this.addr, false, mat3array ); - ].filter( filterEmptyLine ).join( '\n' ); + copyArray( cache, elements ); - if ( prefixFragment.length > 0 ) { + } - prefixFragment += '\n'; + } - } + function setValueM4( gl, v ) { - } else { + var cache = this.cache; + var elements = v.elements; - prefixVertex = [ + if ( elements === undefined ) { - 'precision ' + parameters.precision + ' float;', - 'precision ' + parameters.precision + ' int;', + if ( arraysEqual( cache, v ) ) { return; } - '#define SHADER_NAME ' + shader.name, + gl.uniformMatrix4fv( this.addr, false, v ); - customDefines, + copyArray( cache, v ); - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', + } else { - '#define GAMMA_FACTOR ' + gammaFactorDefine, + if ( arraysEqual( cache, elements ) ) { return; } - '#define MAX_BONES ' + parameters.maxBones, - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', + mat4array.set( elements ); - 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.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', + gl.uniformMatrix4fv( this.addr, false, mat4array ); - parameters.flatShading ? '#define FLAT_SHADED' : '', + copyArray( cache, elements ); - 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 : '', + // Single texture (2D / Cube) - parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', + function setValueT1( gl, v, textures ) { - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - parameters.logarithmicDepthBuffer && ( capabilities.isWebGL2 || extensions.get( 'EXT_frag_depth' ) ) ? '#define USE_LOGDEPTHBUF_EXT' : '', + var cache = this.cache; + var unit = textures.allocateTextureUnit(); - 'uniform mat4 modelMatrix;', - 'uniform mat4 modelViewMatrix;', - 'uniform mat4 projectionMatrix;', - 'uniform mat4 viewMatrix;', - 'uniform mat3 normalMatrix;', - 'uniform vec3 cameraPosition;', + if ( cache[ 0 ] !== unit ) { - 'attribute vec3 position;', - 'attribute vec3 normal;', - 'attribute vec2 uv;', + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - '#ifdef USE_COLOR', + } - ' attribute vec3 color;', + textures.safeSetTexture2D( v || emptyTexture, unit ); - '#endif', + } - '#ifdef USE_MORPHTARGETS', + function setValueT2DArray1( gl, v, textures ) { - ' attribute vec3 morphTarget0;', - ' attribute vec3 morphTarget1;', - ' attribute vec3 morphTarget2;', - ' attribute vec3 morphTarget3;', + var cache = this.cache; + var unit = textures.allocateTextureUnit(); - ' #ifdef USE_MORPHNORMALS', + if ( cache[ 0 ] !== unit ) { - ' attribute vec3 morphNormal0;', - ' attribute vec3 morphNormal1;', - ' attribute vec3 morphNormal2;', - ' attribute vec3 morphNormal3;', + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - ' #else', + } - ' attribute vec3 morphTarget4;', - ' attribute vec3 morphTarget5;', - ' attribute vec3 morphTarget6;', - ' attribute vec3 morphTarget7;', + textures.setTexture2DArray( v || emptyTexture2dArray, unit ); - ' #endif', + } - '#endif', + function setValueT3D1( gl, v, textures ) { - '#ifdef USE_SKINNING', + var cache = this.cache; + var unit = textures.allocateTextureUnit(); - ' attribute vec4 skinIndex;', - ' attribute vec4 skinWeight;', + if ( cache[ 0 ] !== unit ) { - '#endif', + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - '\n' + } - ].filter( filterEmptyLine ).join( '\n' ); + textures.setTexture3D( v || emptyTexture3d, unit ); - prefixFragment = [ + } - customExtensions, + function setValueT6( gl, v, textures ) { - 'precision ' + parameters.precision + ' float;', - 'precision ' + parameters.precision + ' int;', + var cache = this.cache; + var unit = textures.allocateTextureUnit(); - '#define SHADER_NAME ' + shader.name, + if ( cache[ 0 ] !== unit ) { - customDefines, + gl.uniform1i( this.addr, unit ); + cache[ 0 ] = unit; - parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer + } - '#define GAMMA_FACTOR ' + gammaFactorDefine, + textures.safeSetTextureCube( v || emptyCubeTexture, unit ); - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp ) ? '#define FOG_EXP2' : '', + } - parameters.map ? '#define USE_MAP' : '', - 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.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', - parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', - parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - parameters.vertexColors ? '#define USE_COLOR' : '', + // Integer / Boolean vectors or arrays thereof (always flat arrays) - parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', + function setValueV1i( gl, v ) { - parameters.flatShading ? '#define FLAT_SHADED' : '', + var cache = this.cache; - parameters.doubleSided ? '#define DOUBLE_SIDED' : '', - parameters.flipSided ? '#define FLIP_SIDED' : '', + if ( cache[ 0 ] === v ) { return; } - parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', - parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', + gl.uniform1i( this.addr, v ); - parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', + cache[ 0 ] = v; - parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', + } - parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', - parameters.logarithmicDepthBuffer && ( capabilities.isWebGL2 || extensions.get( 'EXT_frag_depth' ) ) ? '#define USE_LOGDEPTHBUF_EXT' : '', + function setValueV2i( gl, v ) { - parameters.envMap && ( capabilities.isWebGL2 || extensions.get( 'EXT_shader_texture_lod' ) ) ? '#define TEXTURE_LOD_EXT' : '', + var cache = this.cache; - 'uniform mat4 viewMatrix;', - 'uniform vec3 cameraPosition;', + if ( arraysEqual( cache, v ) ) { return; } - ( 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 ) : '', + gl.uniform2iv( this.addr, v ); - parameters.dithering ? '#define DITHERING' : '', + copyArray( cache, v ); - ( parameters.outputEncoding || parameters.mapEncoding || parameters.matcapEncoding || parameters.envMapEncoding || parameters.emissiveMapEncoding ) ? - ShaderChunk[ 'encodings_pars_fragment' ] : '', // this code is required here because it is used by the various encoding/decoding function defined below - parameters.mapEncoding ? getTexelDecodingFunction( 'mapTexelToLinear', parameters.mapEncoding ) : '', - parameters.matcapEncoding ? getTexelDecodingFunction( 'matcapTexelToLinear', parameters.matcapEncoding ) : '', - parameters.envMapEncoding ? getTexelDecodingFunction( 'envMapTexelToLinear', parameters.envMapEncoding ) : '', - parameters.emissiveMapEncoding ? getTexelDecodingFunction( 'emissiveMapTexelToLinear', parameters.emissiveMapEncoding ) : '', - parameters.outputEncoding ? getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ) : '', + } - parameters.depthPacking ? '#define DEPTH_PACKING ' + material.depthPacking : '', + function setValueV3i( gl, v ) { - '\n' + var cache = this.cache; - ].filter( filterEmptyLine ).join( '\n' ); + if ( arraysEqual( cache, v ) ) { return; } - } + gl.uniform3iv( this.addr, v ); - vertexShader = parseIncludes( vertexShader ); - vertexShader = replaceLightNums( vertexShader, parameters ); - vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); + copyArray( cache, v ); - fragmentShader = parseIncludes( fragmentShader ); - fragmentShader = replaceLightNums( fragmentShader, parameters ); - fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); + } - vertexShader = unrollLoops( vertexShader ); - fragmentShader = unrollLoops( fragmentShader ); + function setValueV4i( gl, v ) { - if ( capabilities.isWebGL2 && ! material.isRawShaderMaterial ) { + var cache = this.cache; - var isGLSL3ShaderMaterial = false; + if ( arraysEqual( cache, v ) ) { return; } - var versionRegex = /^\s*#version\s+300\s+es\s*\n/; + gl.uniform4iv( this.addr, v ); - if ( material.isShaderMaterial && - vertexShader.match( versionRegex ) !== null && - fragmentShader.match( versionRegex ) !== null ) { + copyArray( cache, v ); - isGLSL3ShaderMaterial = true; + } - vertexShader = vertexShader.replace( versionRegex, '' ); - fragmentShader = fragmentShader.replace( versionRegex, '' ); + // uint - } + function setValueV1ui( gl, v ) { - // GLSL 3.0 conversion - prefixVertex = [ - '#version 300 es\n', - '#define attribute in', - '#define varying out', - '#define texture2D texture' - ].join( '\n' ) + '\n' + prefixVertex; + var cache = this.cache; - prefixFragment = [ - '#version 300 es\n', - '#define varying in', - isGLSL3ShaderMaterial ? '' : 'out highp vec4 pc_fragColor;', - isGLSL3ShaderMaterial ? '' : '#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; + if ( cache[ 0 ] === v ) { return; } - } + gl.uniform1ui( this.addr, v ); - var vertexGlsl = prefixVertex + vertexShader; - var fragmentGlsl = prefixFragment + fragmentShader; + cache[ 0 ] = v; - // console.log( '*VERTEX*', vertexGlsl ); - // console.log( '*FRAGMENT*', fragmentGlsl ); + } - var glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); - var glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); + // Helper to pick the right setter for the singular case - gl.attachShader( program, glVertexShader ); - gl.attachShader( program, glFragmentShader ); + function getSingularSetter( type ) { - // Force a particular attribute to index 0. + switch ( type ) { - if ( material.index0AttributeName !== undefined ) { + case 0x1406: return setValueV1f; // FLOAT + case 0x8b50: return setValueV2f; // _VEC2 + case 0x8b51: return setValueV3f; // _VEC3 + case 0x8b52: return setValueV4f; // _VEC4 - gl.bindAttribLocation( program, 0, material.index0AttributeName ); + case 0x8b5a: return setValueM2; // _MAT2 + case 0x8b5b: return setValueM3; // _MAT3 + case 0x8b5c: return setValueM4; // _MAT4 - } else if ( parameters.morphTargets === true ) { + 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 - // programs with morphTargets displace position out of attribute 0 - gl.bindAttribLocation( program, 0, 'position' ); + case 0x1405: return setValueV1ui; // UINT - } + 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; - gl.linkProgram( program ); + case 0x8b5f: // SAMPLER_3D + case 0x8dcb: // INT_SAMPLER_3D + case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D + return setValueT3D1; - var programLog = gl.getProgramInfoLog( program ).trim(); - var vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); - var fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); + case 0x8b60: // SAMPLER_CUBE + case 0x8dcc: // INT_SAMPLER_CUBE + case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE + case 0x8dc5: // SAMPLER_CUBE_SHADOW + return setValueT6; - var runnable = true; - var haveDiagnostics = true; + 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; - // console.log( '**VERTEX**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glVertexShader ) ); - // console.log( '**FRAGMENT**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( glFragmentShader ) ); + } - if ( gl.getProgramParameter( program, 35714 ) === false ) { + } - runnable = false; + // Array of scalars + function setValueV1fArray( gl, v ) { - console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), '35715', gl.getProgramParameter( program, 35715 ), 'gl.getProgramInfoLog', programLog, vertexLog, fragmentLog ); + gl.uniform1fv( this.addr, v ); - } else if ( programLog !== '' ) { + } - console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog ); + // Integer / Boolean vectors or arrays thereof (always flat arrays) + function setValueV1iArray( gl, v ) { - } else if ( vertexLog === '' || fragmentLog === '' ) { + gl.uniform1iv( this.addr, v ); - haveDiagnostics = false; + } - } + function setValueV2iArray( gl, v ) { - if ( haveDiagnostics ) { + gl.uniform2iv( this.addr, v ); - this.diagnostics = { + } - runnable: runnable, - material: material, + function setValueV3iArray( gl, v ) { - programLog: programLog, + gl.uniform3iv( this.addr, v ); - vertexShader: { + } - log: vertexLog, - prefix: prefixVertex + function setValueV4iArray( gl, v ) { - }, + gl.uniform4iv( this.addr, v ); - fragmentShader: { + } - log: fragmentLog, - prefix: prefixFragment - } + // Array of vectors (flat or from THREE classes) - }; + function setValueV2fArray( gl, v ) { - } + var data = flatten( v, this.size, 2 ); - // clean up + gl.uniform2fv( this.addr, data ); - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); + } - // set up caching for uniform locations + function setValueV3fArray( gl, v ) { - var cachedUniforms; + var data = flatten( v, this.size, 3 ); - this.getUniforms = function () { + gl.uniform3fv( this.addr, data ); - if ( cachedUniforms === undefined ) { + } - cachedUniforms = new WebGLUniforms( gl, program, renderer ); + function setValueV4fArray( gl, v ) { - } + var data = flatten( v, this.size, 4 ); - return cachedUniforms; + gl.uniform4fv( this.addr, data ); - }; + } - // set up caching for attribute locations + // Array of matrices (flat or from THREE clases) - var cachedAttributes; + function setValueM2Array( gl, v ) { - this.getAttributes = function () { + var data = flatten( v, this.size, 4 ); - if ( cachedAttributes === undefined ) { + gl.uniformMatrix2fv( this.addr, false, data ); - cachedAttributes = fetchAttributeLocations( gl, program ); + } - } + function setValueM3Array( gl, v ) { - return cachedAttributes; + var data = flatten( v, this.size, 9 ); - }; + gl.uniformMatrix3fv( this.addr, false, data ); - // free resource + } - this.destroy = function () { + function setValueM4Array( gl, v ) { - gl.deleteProgram( program ); - this.program = undefined; + var data = flatten( v, this.size, 16 ); - }; + gl.uniformMatrix4fv( this.addr, false, data ); - // DEPRECATED + } - Object.defineProperties( this, { + // Array of textures (2D / Cube) - uniforms: { - get: function () { + function setValueT1Array( gl, v, textures ) { - console.warn( 'THREE.WebGLProgram: .uniforms is now .getUniforms().' ); - return this.getUniforms(); + var n = v.length; - } - }, + var units = allocTexUnits( textures, n ); - attributes: { - get: function () { + gl.uniform1iv( this.addr, units ); - console.warn( 'THREE.WebGLProgram: .attributes is now .getAttributes().' ); - return this.getAttributes(); + for ( var i = 0; i !== n; ++ i ) { - } - } + textures.safeSetTexture2D( v[ i ] || emptyTexture, units[ i ] ); - } ); + } + } - // + function setValueT6Array( gl, v, textures ) { - this.name = shader.name; - this.id = programIdCount ++; - this.code = code; - this.usedTimes = 1; - this.program = program; - this.vertexShader = glVertexShader; - this.fragmentShader = glFragmentShader; + var n = v.length; - return this; + var units = allocTexUnits( textures, n ); - } + gl.uniform1iv( this.addr, units ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + for ( var i = 0; i !== n; ++ i ) { - function WebGLPrograms( renderer, extensions, capabilities ) { + textures.safeSetTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); - var programs = []; + } - var shaderIDs = { - MeshDepthMaterial: 'depth', - MeshDistanceMaterial: 'distanceRGBA', - MeshNormalMaterial: 'normal', - MeshBasicMaterial: 'basic', - MeshLambertMaterial: 'lambert', - MeshPhongMaterial: 'phong', - MeshToonMaterial: 'phong', - MeshStandardMaterial: 'physical', - MeshPhysicalMaterial: 'physical', - MeshMatcapMaterial: 'matcap', - LineBasicMaterial: 'basic', - LineDashedMaterial: 'dashed', - PointsMaterial: 'points', - ShadowMaterial: 'shadow', - SpriteMaterial: 'sprite' - }; + } - var parameterNames = [ - "precision", "supportsVertexTextures", "map", "mapEncoding", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding", - "lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "displacementMap", "specularMap", - "roughnessMap", "metalnessMap", "gradientMap", - "alphaMap", "combine", "vertexColors", "fog", "useFog", "fogExp", - "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", - "maxBones", "useVertexTexture", "morphTargets", "morphNormals", - "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", - "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights", - "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights', - "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering" - ]; + // Helper to pick the right setter for a pure (bottom-level) array + function getPureArraySetter( type ) { - function allocateBones( object ) { + switch ( type ) { - var skeleton = object.skeleton; - var bones = skeleton.bones; + case 0x1406: return setValueV1fArray; // FLOAT + case 0x8b50: return setValueV2fArray; // _VEC2 + case 0x8b51: return setValueV3fArray; // _VEC3 + case 0x8b52: return setValueV4fArray; // _VEC4 - if ( capabilities.floatVertexTextures ) { + case 0x8b5a: return setValueM2Array; // _MAT2 + case 0x8b5b: return setValueM3Array; // _MAT3 + case 0x8b5c: return setValueM4Array; // _MAT4 - return 1024; + 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 - } else { + 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; - // 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) + case 0x8b60: // SAMPLER_CUBE + case 0x8dcc: // INT_SAMPLER_CUBE + case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE + case 0x8dc5: // SAMPLER_CUBE_SHADOW + return setValueT6Array; - var nVertexUniforms = capabilities.maxVertexUniforms; - var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); + } - var maxBones = Math.min( nVertexMatrices, bones.length ); + } - if ( maxBones < bones.length ) { + // --- Uniform Classes --- - console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' ); - return 0; + function SingleUniform( id, activeInfo, addr ) { - } + this.id = id; + this.addr = addr; + this.cache = []; + this.setValue = getSingularSetter( activeInfo.type ); - return maxBones; + // this.path = activeInfo.name; // DEBUG - } + } - } + function PureArrayUniform( id, activeInfo, addr ) { - function getTextureEncodingFromMap( map, gammaOverrideLinear ) { + this.id = id; + this.addr = addr; + this.cache = []; + this.size = activeInfo.size; + this.setValue = getPureArraySetter( activeInfo.type ); - var encoding; + // this.path = activeInfo.name; // DEBUG - if ( ! map ) { + } - encoding = LinearEncoding; + PureArrayUniform.prototype.updateCache = function ( data ) { - } else if ( map.isTexture ) { + var cache = this.cache; - encoding = map.encoding; + if ( data instanceof Float32Array && cache.length !== data.length ) { - } else if ( map.isWebGLRenderTarget ) { + this.cache = new Float32Array( data.length ); - console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." ); - encoding = map.texture.encoding; + } - } + copyArray( cache, data ); - // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point. - if ( encoding === LinearEncoding && gammaOverrideLinear ) { + }; - encoding = GammaEncoding; + function StructuredUniform( id ) { - } + this.id = id; - return encoding; + this.seq = []; + this.map = {}; - } + } - this.getParameters = function ( material, lights, shadows, fog, nClipPlanes, nClipIntersection, object ) { + StructuredUniform.prototype.setValue = function ( gl, value, textures ) { - var shaderID = shaderIDs[ material.type ]; + var seq = this.seq; - // heuristics to create shader parameters according to lights in the scene - // (not to blow over maxLights budget) + for ( var i = 0, n = seq.length; i !== n; ++ i ) { - var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0; - var precision = capabilities.precision; + var u = seq[ i ]; + u.setValue( gl, value[ u.id ], textures ); - if ( material.precision !== null ) { + } - precision = capabilities.getMaxPrecision( material.precision ); + }; - if ( precision !== material.precision ) { + // --- Top-level --- - console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); + // Parser - builds up the property tree from the path strings - } + var RePathPart = /([\w\d_]+)(\])?(\[|\.)?/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. - var currentRenderTarget = renderer.getRenderTarget(); + function addUniform( container, uniformObject ) { - var parameters = { + container.seq.push( uniformObject ); + container.map[ uniformObject.id ] = uniformObject; - shaderID: shaderID, + } - precision: precision, - supportsVertexTextures: capabilities.vertexTextures, - outputEncoding: getTextureEncodingFromMap( ( ! currentRenderTarget ) ? null : currentRenderTarget.texture, renderer.gammaOutput ), - map: !! material.map, - mapEncoding: getTextureEncodingFromMap( material.map, renderer.gammaInput ), - matcap: !! material.matcap, - matcapEncoding: getTextureEncodingFromMap( material.matcap, renderer.gammaInput ), - envMap: !! material.envMap, - envMapMode: material.envMap && material.envMap.mapping, - envMapEncoding: getTextureEncodingFromMap( material.envMap, renderer.gammaInput ), - envMapCubeUV: ( !! material.envMap ) && ( ( material.envMap.mapping === CubeUVReflectionMapping ) || ( material.envMap.mapping === CubeUVRefractionMapping ) ), - lightMap: !! material.lightMap, - aoMap: !! material.aoMap, - emissiveMap: !! material.emissiveMap, - emissiveMapEncoding: getTextureEncodingFromMap( material.emissiveMap, renderer.gammaInput ), - bumpMap: !! material.bumpMap, - normalMap: !! material.normalMap, - objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, - displacementMap: !! material.displacementMap, - roughnessMap: !! material.roughnessMap, - metalnessMap: !! material.metalnessMap, - specularMap: !! material.specularMap, - alphaMap: !! material.alphaMap, + function parseUniform( activeInfo, addr, container ) { - gradientMap: !! material.gradientMap, + var path = activeInfo.name, + pathLength = path.length; - combine: material.combine, + // reset RegExp object, because of the early exit of a previous run + RePathPart.lastIndex = 0; - vertexColors: material.vertexColors, + while ( true ) { - fog: !! fog, - useFog: material.fog, - fogExp: ( fog && fog.isFogExp2 ), + var match = RePathPart.exec( path ), + matchEnd = RePathPart.lastIndex; - flatShading: material.flatShading, + var id = match[ 1 ], + idIsIndex = match[ 2 ] === ']', + subscript = match[ 3 ]; - sizeAttenuation: material.sizeAttenuation, - logarithmicDepthBuffer: capabilities.logarithmicDepthBuffer, + if ( idIsIndex ) { id = id | 0; } // convert to integer - skinning: material.skinning && maxBones > 0, - maxBones: maxBones, - useVertexTexture: capabilities.floatVertexTextures, + if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { - morphTargets: material.morphTargets, - morphNormals: material.morphNormals, - maxMorphTargets: renderer.maxMorphTargets, - maxMorphNormals: renderer.maxMorphNormals, + // bare name or "pure" bottom-level array "[0]" suffix - numDirLights: lights.directional.length, - numPointLights: lights.point.length, - numSpotLights: lights.spot.length, - numRectAreaLights: lights.rectArea.length, - numHemiLights: lights.hemi.length, + addUniform( container, subscript === undefined ? + new SingleUniform( id, activeInfo, addr ) : + new PureArrayUniform( id, activeInfo, addr ) ); - numClippingPlanes: nClipPlanes, - numClipIntersection: nClipIntersection, + break; - dithering: material.dithering, + } else { - shadowMapEnabled: renderer.shadowMap.enabled && object.receiveShadow && shadows.length > 0, - shadowMapType: renderer.shadowMap.type, + // step into inner node / create it in case it doesn't exist - toneMapping: renderer.toneMapping, - physicallyCorrectLights: renderer.physicallyCorrectLights, + var map = container.map; + var next = map[ id ]; - premultipliedAlpha: material.premultipliedAlpha, + if ( next === undefined ) { - alphaTest: material.alphaTest, - doubleSided: material.side === DoubleSide, - flipSided: material.side === BackSide, + next = new StructuredUniform( id ); + addUniform( container, next ); - depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false + } - }; + container = next; - return parameters; + } - }; + } - this.getProgramCode = function ( material, parameters ) { + } - var array = []; + // Root Container - if ( parameters.shaderID ) { + function WebGLUniforms( gl, program ) { - array.push( parameters.shaderID ); + this.seq = []; + this.map = {}; - } else { + var n = gl.getProgramParameter( program, 35718 ); - array.push( material.fragmentShader ); - array.push( material.vertexShader ); + for ( var i = 0; i < n; ++ i ) { - } + var info = gl.getActiveUniform( program, i ), + addr = gl.getUniformLocation( program, info.name ); - if ( material.defines !== undefined ) { + parseUniform( info, addr, this ); - for ( var name in material.defines ) { + } - array.push( name ); - array.push( material.defines[ name ] ); + } - } + WebGLUniforms.prototype.setValue = function ( gl, name, value, textures ) { - } + var u = this.map[ name ]; - for ( var i = 0; i < parameterNames.length; i ++ ) { + if ( u !== undefined ) { u.setValue( gl, value, textures ); } - array.push( parameters[ parameterNames[ i ] ] ); + }; - } + WebGLUniforms.prototype.setOptional = function ( gl, object, name ) { - array.push( material.onBeforeCompile.toString() ); + var v = object[ name ]; - array.push( renderer.gammaOutput ); + if ( v !== undefined ) { this.setValue( gl, name, v ); } - array.push( renderer.gammaFactor ); + }; - return array.join(); - }; + // Static interface - this.acquireProgram = function ( material, shader, parameters, code ) { + WebGLUniforms.upload = function ( gl, seq, values, textures ) { - var program; + for ( var i = 0, n = seq.length; i !== n; ++ i ) { - // Check if code has been already compiled - for ( var p = 0, pl = programs.length; p < pl; p ++ ) { + var u = seq[ i ], + v = values[ u.id ]; - var programInfo = programs[ p ]; + if ( v.needsUpdate !== false ) { - if ( programInfo.code === code ) { + // note: always updating when .needsUpdate is undefined + u.setValue( gl, v.value, textures ); - program = programInfo; - ++ program.usedTimes; + } - break; + } - } + }; - } + WebGLUniforms.seqWithValue = function ( seq, values ) { - if ( program === undefined ) { + var r = []; - program = new WebGLProgram( renderer, extensions, code, material, shader, parameters, capabilities ); - programs.push( program ); + for ( var i = 0, n = seq.length; i !== n; ++ i ) { - } + var u = seq[ i ]; + if ( u.id in values ) { r.push( u ); } - return program; + } - }; + return r; - this.releaseProgram = function ( program ) { + }; - if ( -- program.usedTimes === 0 ) { + function WebGLShader( gl, type, string ) { - // Remove from unordered set - var i = programs.indexOf( program ); - programs[ i ] = programs[ programs.length - 1 ]; - programs.pop(); + var shader = gl.createShader( type ); - // Free WebGL resources - program.destroy(); + gl.shaderSource( shader, string ); + gl.compileShader( shader ); - } + return shader; - }; + } - // Exposed for resource monitoring & error feedback via renderer.info: - this.programs = programs; + var programIdCount = 0; - } + function addLineNumbers( string ) { - /** - * @author fordacious / fordacious.github.io - */ + var lines = string.split( '\n' ); - function WebGLProperties() { + for ( var i = 0; i < lines.length; i ++ ) { - var properties = new WeakMap(); + lines[ i ] = ( i + 1 ) + ': ' + lines[ i ]; - function get( object ) { + } - var map = properties.get( object ); + return lines.join( '\n' ); - if ( map === undefined ) { + } - map = {}; - properties.set( object, map ); + function getEncodingComponents( encoding ) { - } + switch ( encoding ) { - return map; + 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 remove( object ) { + } - properties.delete( object ); + function getShaderErrors( gl, shader, type ) { - } + var status = gl.getShaderParameter( shader, 35713 ); + var log = gl.getShaderInfoLog( shader ).trim(); - function update( object, key, value ) { + if ( status && log === '' ) { return ''; } - properties.get( object )[ key ] = value; + // --enable-privileged-webgl-extension + // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); - } + var source = gl.getShaderSource( shader ); - function dispose() { + return 'THREE.WebGLShader: gl.getShaderInfoLog() ' + type + '\n' + log + addLineNumbers( source ); - properties = new WeakMap(); + } - } + function getTexelDecodingFunction( functionName, encoding ) { - return { - get: get, - remove: remove, - update: update, - dispose: dispose - }; + var components = getEncodingComponents( encoding ); + return 'vec4 ' + functionName + '( vec4 value ) { return ' + components[ 0 ] + 'ToLinear' + components[ 1 ] + '; }'; } - /** - * @author mrdoob / http://mrdoob.com/ - */ + function getTexelEncodingFunction( functionName, encoding ) { - function painterSortStable( a, b ) { + var components = getEncodingComponents( encoding ); + return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; - if ( a.renderOrder !== b.renderOrder ) { + } - return a.renderOrder - b.renderOrder; + function getToneMappingFunction( functionName, toneMapping ) { - } else if ( a.program && b.program && a.program !== b.program ) { + var toneMappingName; - return a.program.id - b.program.id; + switch ( toneMapping ) { - } else if ( a.material.id !== b.material.id ) { + case LinearToneMapping: + toneMappingName = 'Linear'; + break; - return a.material.id - b.material.id; + case ReinhardToneMapping: + toneMappingName = 'Reinhard'; + break; - } else if ( a.z !== b.z ) { + case CineonToneMapping: + toneMappingName = 'OptimizedCineon'; + break; - return a.z - b.z; + case ACESFilmicToneMapping: + toneMappingName = 'ACESFilmic'; + break; - } else { + case CustomToneMapping: + toneMappingName = 'Custom'; + break; - return a.id - b.id; + default: + console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping ); + toneMappingName = 'Linear'; } + return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; + } - function reversePainterSortStable( a, b ) { + function generateExtensions( parameters ) { - if ( a.renderOrder !== b.renderOrder ) { + var 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.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' + ]; - return a.renderOrder - b.renderOrder; + return chunks.filter( filterEmptyLine ).join( '\n' ); - } if ( a.z !== b.z ) { + } - return b.z - a.z; + function generateDefines( defines ) { - } else { + var chunks = []; - return a.id - b.id; + for ( var name in defines ) { - } + var value = defines[ name ]; - } + if ( value === false ) { continue; } + chunks.push( '#define ' + name + ' ' + value ); - function WebGLRenderList() { + } - var renderItems = []; - var renderItemsIndex = 0; + return chunks.join( '\n' ); - var opaque = []; - var transparent = []; + } - function init() { + function fetchAttributeLocations( gl, program ) { - renderItemsIndex = 0; + var attributes = {}; - opaque.length = 0; - transparent.length = 0; + var n = gl.getProgramParameter( program, 35721 ); - } + for ( var i = 0; i < n; i ++ ) { - function push( object, geometry, material, z, group ) { + var info = gl.getActiveAttrib( program, i ); + var name = info.name; - var renderItem = renderItems[ renderItemsIndex ]; + // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); - if ( renderItem === undefined ) { + attributes[ name ] = gl.getAttribLocation( program, name ); - renderItem = { - id: object.id, - object: object, - geometry: geometry, - material: material, - program: material.program, - renderOrder: object.renderOrder, - z: z, - group: group - }; + } - renderItems[ renderItemsIndex ] = renderItem; + return attributes; - } else { + } - renderItem.id = object.id; - renderItem.object = object; - renderItem.geometry = geometry; - renderItem.material = material; - renderItem.program = material.program; - renderItem.renderOrder = object.renderOrder; - renderItem.z = z; - renderItem.group = group; + function filterEmptyLine( string ) { - } + return string !== ''; + + } + function replaceLightNums( string, parameters ) { - ( material.transparent === true ? transparent : opaque ).push( renderItem ); + 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 ); - renderItemsIndex ++; + } - } + function replaceClippingPlaneNums( string, parameters ) { - function sort() { + return string + .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) + .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); - if ( opaque.length > 1 ) opaque.sort( painterSortStable ); - if ( transparent.length > 1 ) transparent.sort( reversePainterSortStable ); + } - } + // Resolve Includes - return { - opaque: opaque, - transparent: transparent, + var includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; - init: init, - push: push, + function resolveIncludes( string ) { - sort: sort - }; + return string.replace( includePattern, includeReplacer ); } - function WebGLRenderLists() { + function includeReplacer( match, include ) { - var lists = {}; + var string = ShaderChunk[ include ]; - function get( scene, camera ) { + if ( string === undefined ) { - var hash = scene.id + ',' + camera.id; - var list = lists[ hash ]; + throw new Error( 'Can not resolve #include <' + include + '>' ); - if ( list === undefined ) { + } - // console.log( 'THREE.WebGLRenderLists:', hash ); + return resolveIncludes( string ); - list = new WebGLRenderList(); - lists[ hash ] = list; + } - } + // Unroll Loops - return list; + var deprecatedUnrollLoopPattern = /#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g; + var unrollLoopPattern = /#pragma unroll_loop_start[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}[\s]+?#pragma unroll_loop_end/g; - } + function unrollLoops( string ) { - function dispose() { + return string + .replace( unrollLoopPattern, loopReplacer ) + .replace( deprecatedUnrollLoopPattern, deprecatedLoopReplacer ); - lists = {}; + } - } + function deprecatedLoopReplacer( match, start, end, snippet ) { - return { - get: get, - dispose: dispose - }; + console.warn( 'WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead.' ); + return loopReplacer( match, start, end, snippet ); } - /** - * @author mrdoob / http://mrdoob.com/ - */ + function loopReplacer( match, start, end, snippet ) { - function UniformsCache() { + var string = ''; - var lights = {}; + for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) { - return { + string += snippet + .replace( /\[ i \]/g, '[ ' + i + ' ]' ) + .replace( /UNROLLED_LOOP_INDEX/g, i ); - get: function ( light ) { + } - if ( lights[ light.id ] !== undefined ) { + return string; - return lights[ light.id ]; + } - } + // - var uniforms; + function generatePrecision( parameters ) { - switch ( light.type ) { + var precisionstring = "precision " + parameters.precision + " float;\nprecision " + parameters.precision + " int;"; - case 'DirectionalLight': - uniforms = { - direction: new Vector3(), - color: new Color(), + if ( parameters.precision === "highp" ) { - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; + precisionstring += "\n#define HIGH_PRECISION"; - case 'SpotLight': - uniforms = { - position: new Vector3(), - direction: new Vector3(), - color: new Color(), - distance: 0, - coneCos: 0, - penumbraCos: 0, - decay: 0, + } else if ( parameters.precision === "mediump" ) { - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2() - }; - break; + precisionstring += "\n#define MEDIUM_PRECISION"; - case 'PointLight': - uniforms = { - position: new Vector3(), - color: new Color(), - distance: 0, - decay: 0, + } else if ( parameters.precision === "lowp" ) { - shadow: false, - shadowBias: 0, - shadowRadius: 1, - shadowMapSize: new Vector2(), - shadowCameraNear: 1, - shadowCameraFar: 1000 - }; - break; + precisionstring += "\n#define LOW_PRECISION"; - 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() - // TODO (abelnation): set RectAreaLight shadow uniforms - }; - break; + return precisionstring; - } + } - lights[ light.id ] = uniforms; + function generateShadowMapTypeDefine( parameters ) { - return uniforms; + var shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; - } + if ( parameters.shadowMapType === PCFShadowMap ) { - }; + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; - } + } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { - var count = 0; + shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; - function WebGLLights() { + } else if ( parameters.shadowMapType === VSMShadowMap ) { - var cache = new UniformsCache(); + shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; - var state = { + } - id: count ++, + return shadowMapTypeDefine; - hash: { - stateID: - 1, - directionalLength: - 1, - pointLength: - 1, - spotLength: - 1, - rectAreaLength: - 1, - hemiLength: - 1, - shadowsLength: - 1 - }, + } - ambient: [ 0, 0, 0 ], - directional: [], - directionalShadowMap: [], - directionalShadowMatrix: [], - spot: [], - spotShadowMap: [], - spotShadowMatrix: [], - rectArea: [], - point: [], - pointShadowMap: [], - pointShadowMatrix: [], - hemi: [] + function generateEnvMapTypeDefine( parameters ) { - }; + var envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; - var vector3 = new Vector3(); - var matrix4 = new Matrix4(); - var matrix42 = new Matrix4(); + if ( parameters.envMap ) { - function setup( lights, shadows, camera ) { + switch ( parameters.envMapMode ) { - var r = 0, g = 0, b = 0; + case CubeReflectionMapping: + case CubeRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; + break; - var directionalLength = 0; - var pointLength = 0; - var spotLength = 0; - var rectAreaLength = 0; - var hemiLength = 0; + case CubeUVReflectionMapping: + case CubeUVRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; + break; - var viewMatrix = camera.matrixWorldInverse; + case EquirectangularReflectionMapping: + case EquirectangularRefractionMapping: + envMapTypeDefine = 'ENVMAP_TYPE_EQUIREC'; + break; - for ( var i = 0, l = lights.length; i < l; i ++ ) { + } - var light = lights[ i ]; + } - var color = light.color; - var intensity = light.intensity; - var distance = light.distance; + return envMapTypeDefine; - var shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; + } - if ( light.isAmbientLight ) { + function generateEnvMapModeDefine( parameters ) { - r += color.r * intensity; - g += color.g * intensity; - b += color.b * intensity; + var envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; - } else if ( light.isDirectionalLight ) { + if ( parameters.envMap ) { - var uniforms = cache.get( light ); + switch ( parameters.envMapMode ) { - uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); + case CubeRefractionMapping: + case EquirectangularRefractionMapping: + case CubeUVRefractionMapping: - uniforms.shadow = light.castShadow; + envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; + break; - if ( light.castShadow ) { + } - var shadow = light.shadow; + } - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; + return envMapModeDefine; - } + } - state.directionalShadowMap[ directionalLength ] = shadowMap; - state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - state.directional[ directionalLength ] = uniforms; + function generateEnvMapBlendingDefine( parameters ) { - directionalLength ++; + var envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; - } else if ( light.isSpotLight ) { + if ( parameters.envMap ) { - var uniforms = cache.get( light ); + switch ( parameters.combine ) { - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + case MultiplyOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; + break; - uniforms.color.copy( color ).multiplyScalar( intensity ); - uniforms.distance = distance; + case MixOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; + break; - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - vector3.setFromMatrixPosition( light.target.matrixWorld ); - uniforms.direction.sub( vector3 ); - uniforms.direction.transformDirection( viewMatrix ); + case AddOperation: + envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; + break; - uniforms.coneCos = Math.cos( light.angle ); - uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); - uniforms.decay = light.decay; + } - uniforms.shadow = light.castShadow; + } - if ( light.castShadow ) { + return envMapBlendingDefine; - var shadow = light.shadow; + } - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; + function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { - } + var gl = renderer.getContext(); - state.spotShadowMap[ spotLength ] = shadowMap; - state.spotShadowMatrix[ spotLength ] = light.shadow.matrix; - state.spot[ spotLength ] = uniforms; + var defines = parameters.defines; - spotLength ++; + var vertexShader = parameters.vertexShader; + var fragmentShader = parameters.fragmentShader; - } else if ( light.isRectAreaLight ) { + var shadowMapTypeDefine = generateShadowMapTypeDefine( parameters ); + var envMapTypeDefine = generateEnvMapTypeDefine( parameters ); + var envMapModeDefine = generateEnvMapModeDefine( parameters ); + var envMapBlendingDefine = generateEnvMapBlendingDefine( parameters ); - var uniforms = cache.get( light ); - // (a) intensity is the total visible light emitted - //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) ); + var gammaFactorDefine = ( renderer.gammaFactor > 0 ) ? renderer.gammaFactor : 1.0; - // (b) intensity is the brightness of the light - uniforms.color.copy( color ).multiplyScalar( intensity ); + var customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + var customDefines = generateDefines( defines ); - // extract local rotation of light to derive width/height half vectors - matrix42.identity(); - matrix4.copy( light.matrixWorld ); - matrix4.premultiply( viewMatrix ); - matrix42.extractRotation( matrix4 ); + var program = gl.createProgram(); - uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); - uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); + var prefixVertex, prefixFragment; - uniforms.halfWidth.applyMatrix4( matrix42 ); - uniforms.halfHeight.applyMatrix4( matrix42 ); + if ( parameters.isRawShaderMaterial ) { - // TODO (abelnation): RectAreaLight distance? - // uniforms.distance = distance; + prefixVertex = [ - state.rectArea[ rectAreaLength ] = uniforms; + customDefines - rectAreaLength ++; + ].filter( filterEmptyLine ).join( '\n' ); - } else if ( light.isPointLight ) { + if ( prefixVertex.length > 0 ) { - var uniforms = cache.get( light ); + prefixVertex += '\n'; - uniforms.position.setFromMatrixPosition( light.matrixWorld ); - uniforms.position.applyMatrix4( viewMatrix ); + } - uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); - uniforms.distance = light.distance; - uniforms.decay = light.decay; + prefixFragment = [ - uniforms.shadow = light.castShadow; + customExtensions, + customDefines - if ( light.castShadow ) { + ].filter( filterEmptyLine ).join( '\n' ); - var shadow = light.shadow; + if ( prefixFragment.length > 0 ) { - uniforms.shadowBias = shadow.bias; - uniforms.shadowRadius = shadow.radius; - uniforms.shadowMapSize = shadow.mapSize; - uniforms.shadowCameraNear = shadow.camera.near; - uniforms.shadowCameraFar = shadow.camera.far; + prefixFragment += '\n'; - } + } - state.pointShadowMap[ pointLength ] = shadowMap; - state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; - state.point[ pointLength ] = uniforms; + } else { - pointLength ++; + prefixVertex = [ - } else if ( light.isHemisphereLight ) { + generatePrecision( parameters ), - var uniforms = cache.get( light ); + '#define SHADER_NAME ' + parameters.shaderName, - uniforms.direction.setFromMatrixPosition( light.matrixWorld ); - uniforms.direction.transformDirection( viewMatrix ); - uniforms.direction.normalize(); + customDefines, - uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); - uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); + parameters.instancing ? '#define USE_INSTANCING' : '', + parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - state.hemi[ hemiLength ] = uniforms; + '#define GAMMA_FACTOR ' + gammaFactorDefine, - hemiLength ++; + '#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.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', + parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - state.ambient[ 0 ] = r; - state.ambient[ 1 ] = g; - state.ambient[ 2 ] = b; + parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', + parameters.vertexUvs ? '#define USE_UV' : '', + parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', - state.directional.length = directionalLength; - state.spot.length = spotLength; - state.rectArea.length = rectAreaLength; - state.point.length = pointLength; - state.hemi.length = hemiLength; + parameters.flatShading ? '#define FLAT_SHADED' : '', - state.hash.stateID = state.id; - state.hash.directionalLength = directionalLength; - state.hash.pointLength = pointLength; - state.hash.spotLength = spotLength; - state.hash.rectAreaLength = rectAreaLength; - state.hash.hemiLength = hemiLength; - state.hash.shadowsLength = shadows.length; + 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' : '', - return { - setup: setup, - state: state - }; + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - } + parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', - /** - * @author Mugen87 / https://github.com/Mugen87 - */ + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - function WebGLRenderState() { + 'uniform mat4 modelMatrix;', + 'uniform mat4 modelViewMatrix;', + 'uniform mat4 projectionMatrix;', + 'uniform mat4 viewMatrix;', + 'uniform mat3 normalMatrix;', + 'uniform vec3 cameraPosition;', + 'uniform bool isOrthographic;', - var lights = new WebGLLights(); + '#ifdef USE_INSTANCING', - var lightsArray = []; - var shadowsArray = []; + ' attribute mat4 instanceMatrix;', - function init() { + '#endif', - lightsArray.length = 0; - shadowsArray.length = 0; + 'attribute vec3 position;', + 'attribute vec3 normal;', + 'attribute vec2 uv;', - } + '#ifdef USE_TANGENT', - function pushLight( light ) { + ' attribute vec4 tangent;', - lightsArray.push( light ); + '#endif', - } + '#ifdef USE_COLOR', - function pushShadow( shadowLight ) { + ' attribute vec3 color;', - shadowsArray.push( shadowLight ); + '#endif', - } + '#ifdef USE_MORPHTARGETS', - function setupLights( camera ) { + ' attribute vec3 morphTarget0;', + ' attribute vec3 morphTarget1;', + ' attribute vec3 morphTarget2;', + ' attribute vec3 morphTarget3;', - lights.setup( lightsArray, shadowsArray, camera ); + ' #ifdef USE_MORPHNORMALS', - } + ' attribute vec3 morphNormal0;', + ' attribute vec3 morphNormal1;', + ' attribute vec3 morphNormal2;', + ' attribute vec3 morphNormal3;', - var state = { - lightsArray: lightsArray, - shadowsArray: shadowsArray, + ' #else', - lights: lights - }; + ' attribute vec3 morphTarget4;', + ' attribute vec3 morphTarget5;', + ' attribute vec3 morphTarget6;', + ' attribute vec3 morphTarget7;', - return { - init: init, - state: state, - setupLights: setupLights, + ' #endif', - pushLight: pushLight, - pushShadow: pushShadow - }; + '#endif', - } + '#ifdef USE_SKINNING', - function WebGLRenderStates() { + ' attribute vec4 skinIndex;', + ' attribute vec4 skinWeight;', - var renderStates = {}; + '#endif', - function get( scene, camera ) { + '\n' - var renderState; + ].filter( filterEmptyLine ).join( '\n' ); - if ( renderStates[ scene.id ] === undefined ) { + prefixFragment = [ - renderState = new WebGLRenderState(); - renderStates[ scene.id ] = {}; - renderStates[ scene.id ][ camera.id ] = renderState; + customExtensions, - } else { + generatePrecision( parameters ), - if ( renderStates[ scene.id ][ camera.id ] === undefined ) { + '#define SHADER_NAME ' + parameters.shaderName, - renderState = new WebGLRenderState(); - renderStates[ scene.id ][ camera.id ] = renderState; + customDefines, - } else { + parameters.alphaTest ? '#define ALPHATEST ' + parameters.alphaTest + ( parameters.alphaTest % 1 ? '' : '.0' ) : '', // add '.0' if integer - renderState = renderStates[ scene.id ][ camera.id ]; + '#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.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', + parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', + parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', + parameters.specularMap ? '#define USE_SPECULARMAP' : '', + parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', + parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', + parameters.alphaMap ? '#define USE_ALPHAMAP' : '', - return renderState; + parameters.sheen ? '#define USE_SHEEN' : '', + parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', - } + parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.vertexColors ? '#define USE_COLOR' : '', + parameters.vertexUvs ? '#define USE_UV' : '', + parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', - function dispose() { + parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', - renderStates = {}; + parameters.flatShading ? '#define FLAT_SHADED' : '', - } + parameters.doubleSided ? '#define DOUBLE_SIDED' : '', + parameters.flipSided ? '#define FLIP_SIDED' : '', - return { - get: get, - dispose: dispose - }; + parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', + parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', - } + parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author bhouston / https://clara.io - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * - * opacity: , - * - * map: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * wireframe: , - * wireframeLinewidth: - * } - */ + parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', - function MeshDepthMaterial( parameters ) { + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', + ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', - Material.call( this ); + ( ( parameters.extensionShaderTextureLOD || parameters.envMap ) && parameters.rendererExtensionShaderTextureLod ) ? '#define TEXTURE_LOD_EXT' : '', - this.type = 'MeshDepthMaterial'; + 'uniform mat4 viewMatrix;', + 'uniform vec3 cameraPosition;', + 'uniform bool isOrthographic;', - this.depthPacking = BasicDepthPacking; + ( 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 ) : '', - this.skinning = false; - this.morphTargets = false; + parameters.dithering ? '#define DITHERING' : '', - this.map = null; + 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.lightMap ? getTexelDecodingFunction( 'lightMapTexelToLinear', parameters.lightMapEncoding ) : '', + getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ), - this.alphaMap = null; + parameters.depthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + '\n' - this.wireframe = false; - this.wireframeLinewidth = 1; + ].filter( filterEmptyLine ).join( '\n' ); - this.fog = false; - this.lights = false; + } - this.setValues( parameters ); + vertexShader = resolveIncludes( vertexShader ); + vertexShader = replaceLightNums( vertexShader, parameters ); + vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); - } + fragmentShader = resolveIncludes( fragmentShader ); + fragmentShader = replaceLightNums( fragmentShader, parameters ); + fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); - MeshDepthMaterial.prototype = Object.create( Material.prototype ); - MeshDepthMaterial.prototype.constructor = MeshDepthMaterial; + vertexShader = unrollLoops( vertexShader ); + fragmentShader = unrollLoops( fragmentShader ); - MeshDepthMaterial.prototype.isMeshDepthMaterial = true; + if ( parameters.isWebGL2 && ! parameters.isRawShaderMaterial ) { - MeshDepthMaterial.prototype.copy = function ( source ) { + // GLSL 3.0 conversion - Material.prototype.copy.call( this, source ); + prefixVertex = [ + '#version 300 es\n', + '#define attribute in', + '#define varying out', + '#define texture2D texture' + ].join( '\n' ) + '\n' + prefixVertex; - this.depthPacking = source.depthPacking; + prefixFragment = [ + '#version 300 es\n', + '#define varying in', + 'out highp vec4 pc_fragColor;', + '#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; - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; + } - this.map = source.map; + var vertexGlsl = prefixVertex + vertexShader; + var fragmentGlsl = prefixFragment + fragmentShader; - this.alphaMap = source.alphaMap; + // console.log( '*VERTEX*', vertexGlsl ); + // console.log( '*FRAGMENT*', fragmentGlsl ); - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + var glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); + var glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; + gl.attachShader( program, glVertexShader ); + gl.attachShader( program, glFragmentShader ); - return this; + // Force a particular attribute to index 0. - }; + if ( parameters.index0AttributeName !== undefined ) { - /** - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * - * referencePosition: , - * nearDistance: , - * farDistance: , - * - * skinning: , - * morphTargets: , - * - * map: new THREE.Texture( ), - * - * alphaMap: new THREE.Texture( ), - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: - * - * } - */ + gl.bindAttribLocation( program, 0, parameters.index0AttributeName ); - function MeshDistanceMaterial( parameters ) { + } else if ( parameters.morphTargets === true ) { - Material.call( this ); + // programs with morphTargets displace position out of attribute 0 + gl.bindAttribLocation( program, 0, 'position' ); - this.type = 'MeshDistanceMaterial'; + } - this.referencePosition = new Vector3(); - this.nearDistance = 1; - this.farDistance = 1000; + gl.linkProgram( program ); - this.skinning = false; - this.morphTargets = false; + // check for link errors + if ( renderer.debug.checkShaderErrors ) { - this.map = null; + var programLog = gl.getProgramInfoLog( program ).trim(); + var vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); + var fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); - this.alphaMap = null; + var runnable = true; + var haveDiagnostics = true; - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + if ( gl.getProgramParameter( program, 35714 ) === false ) { - this.fog = false; - this.lights = false; + runnable = false; - this.setValues( parameters ); + var vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); + var fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); - } + console.error( 'THREE.WebGLProgram: shader error: ', gl.getError(), '35715', gl.getProgramParameter( program, 35715 ), 'gl.getProgramInfoLog', programLog, vertexErrors, fragmentErrors ); - MeshDistanceMaterial.prototype = Object.create( Material.prototype ); - MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial; + } else if ( programLog !== '' ) { - MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true; + console.warn( 'THREE.WebGLProgram: gl.getProgramInfoLog()', programLog ); - MeshDistanceMaterial.prototype.copy = function ( source ) { + } else if ( vertexLog === '' || fragmentLog === '' ) { - Material.prototype.copy.call( this, source ); + haveDiagnostics = false; - this.referencePosition.copy( source.referencePosition ); - this.nearDistance = source.nearDistance; - this.farDistance = source.farDistance; + } - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; + if ( haveDiagnostics ) { - this.map = source.map; + this.diagnostics = { - this.alphaMap = source.alphaMap; + runnable: runnable, - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + programLog: programLog, - return this; + vertexShader: { - }; + log: vertexLog, + prefix: prefixVertex - /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + }, - function WebGLShadowMap( _renderer, _objects, maxTextureSize ) { + fragmentShader: { - var _frustum = new Frustum(), - _projScreenMatrix = new Matrix4(), + log: fragmentLog, + prefix: prefixFragment - _shadowMapSize = new Vector2(), - _maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ), + } - _lookTarget = new Vector3(), - _lightPositionWorld = new Vector3(), + }; - _MorphingFlag = 1, - _SkinningFlag = 2, + } - _NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1, + } - _depthMaterials = new Array( _NumberOfMaterialVariants ), - _distanceMaterials = new Array( _NumberOfMaterialVariants ), + // Clean up - _materialCache = {}; + // Crashes in iOS9 and iOS10. #18402 + // gl.detachShader( program, glVertexShader ); + // gl.detachShader( program, glFragmentShader ); - var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; + gl.deleteShader( glVertexShader ); + gl.deleteShader( glFragmentShader ); - var 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 ) - ]; + // set up caching for uniform locations - var 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 ) - ]; + var cachedUniforms; - var cube2DViewPorts = [ - new Vector4(), new Vector4(), new Vector4(), - new Vector4(), new Vector4(), new Vector4() - ]; + this.getUniforms = function () { - // init + if ( cachedUniforms === undefined ) { - for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) { + cachedUniforms = new WebGLUniforms( gl, program ); - var useMorphing = ( i & _MorphingFlag ) !== 0; - var useSkinning = ( i & _SkinningFlag ) !== 0; + } - var depthMaterial = new MeshDepthMaterial( { + return cachedUniforms; - depthPacking: RGBADepthPacking, + }; - morphTargets: useMorphing, - skinning: useSkinning + // set up caching for attribute locations - } ); + var cachedAttributes; - _depthMaterials[ i ] = depthMaterial; + this.getAttributes = function () { - // + if ( cachedAttributes === undefined ) { - var distanceMaterial = new MeshDistanceMaterial( { + cachedAttributes = fetchAttributeLocations( gl, program ); - morphTargets: useMorphing, - skinning: useSkinning + } - } ); + return cachedAttributes; - _distanceMaterials[ i ] = distanceMaterial; + }; - } + // free resource - // + this.destroy = function () { - var scope = this; + bindingStates.releaseStatesOfProgram( this ); - this.enabled = false; + gl.deleteProgram( program ); + this.program = undefined; - this.autoUpdate = true; - this.needsUpdate = false; + }; - this.type = PCFShadowMap; + // - this.render = function ( lights, scene, camera ) { + this.name = parameters.shaderName; + this.id = programIdCount ++; + this.cacheKey = cacheKey; + this.usedTimes = 1; + this.program = program; + this.vertexShader = glVertexShader; + this.fragmentShader = glFragmentShader; - if ( scope.enabled === false ) return; - if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; + return this; - if ( lights.length === 0 ) return; + } - // TODO Clean up (needed in case of contextlost) - var _gl = _renderer.context; - var _state = _renderer.state; + function WebGLPrograms( renderer, extensions, capabilities, bindingStates ) { - // Set GL state for depth map. - _state.disable( 3042 ); - _state.buffers.color.setClear( 1, 1, 1, 1 ); - _state.buffers.depth.setTest( true ); - _state.setScissorTest( false ); + var programs = []; - // render depth map + var isWebGL2 = capabilities.isWebGL2; + var logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; + var floatVertexTextures = capabilities.floatVertexTextures; + var maxVertexUniforms = capabilities.maxVertexUniforms; + var vertexTextures = capabilities.vertexTextures; - var faceCount; + var precision = capabilities.precision; - for ( var i = 0, il = lights.length; i < il; i ++ ) { + var 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' + }; - var light = lights[ i ]; - var shadow = light.shadow; - var isPointLight = light && light.isPointLight; + var parameterNames = [ + "precision", "isWebGL2", "supportsVertexTextures", "outputEncoding", "instancing", + "map", "mapEncoding", "matcap", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding", "envMapCubeUV", + "lightMap", "lightMapEncoding", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "tangentSpaceNormalMap", "clearcoatMap", "clearcoatRoughnessMap", "clearcoatNormalMap", "displacementMap", "specularMap", + "roughnessMap", "metalnessMap", "gradientMap", + "alphaMap", "combine", "vertexColors", "vertexTangents", "vertexUvs", "uvsVertexOnly", "fog", "useFog", "fogExp2", + "flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning", + "maxBones", "useVertexTexture", "morphTargets", "morphNormals", + "maxMorphTargets", "maxMorphNormals", "premultipliedAlpha", + "numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights", + "numDirLightShadows", "numPointLightShadows", "numSpotLightShadows", + "shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights', + "alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering", + "sheen", "transmissionMap" + ]; - if ( shadow === undefined ) { + function allocateBones( object ) { - console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); - continue; + var skeleton = object.skeleton; + var bones = skeleton.bones; - } + if ( floatVertexTextures ) { - var shadowCamera = shadow.camera; + return 1024; - _shadowMapSize.copy( shadow.mapSize ); - _shadowMapSize.min( _maxShadowMapSize ); + } else { - if ( isPointLight ) { + // default for when object is not specified + // ( for example when prebuilding shader to be used with multiple objects ) + // + // - leave some extra space for other uniforms + // - limit here is ANGLE's 254 max uniform vectors + // (up to 54 should be safe) - var vpWidth = _shadowMapSize.x; - var vpHeight = _shadowMapSize.y; + var nVertexUniforms = maxVertexUniforms; + var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); - // 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 - cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight ); - // negative X - cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight ); - // positive Z - cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight ); - // negative Z - cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight ); - // positive Y - cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight ); - // negative Y - cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight ); - - _shadowMapSize.x *= 4.0; - _shadowMapSize.y *= 2.0; + var maxBones = Math.min( nVertexMatrices, bones.length ); - } + if ( maxBones < bones.length ) { - if ( shadow.map === null ) { + console.warn( 'THREE.WebGLRenderer: Skeleton has ' + bones.length + ' bones. This GPU supports ' + maxBones + '.' ); + return 0; - var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat }; + } - shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - shadow.map.texture.name = light.name + ".shadowMap"; + return maxBones; - shadowCamera.updateProjectionMatrix(); + } - } + } - if ( shadow.isSpotLightShadow ) { + function getTextureEncodingFromMap( map ) { - shadow.update( light ); + var encoding; - } + if ( ! map ) { - var shadowMap = shadow.map; - var shadowMatrix = shadow.matrix; + encoding = LinearEncoding; - _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); - shadowCamera.position.copy( _lightPositionWorld ); + } else if ( map.isTexture ) { - if ( isPointLight ) { + encoding = map.encoding; - faceCount = 6; + } else if ( map.isWebGLRenderTarget ) { - // for point lights we set the shadow matrix to be a translation-only matrix - // equal to inverse of the light's position + console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." ); + encoding = map.texture.encoding; - shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); + } - } else { + return encoding; - faceCount = 1; + } - _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); - shadowCamera.lookAt( _lookTarget ); - shadowCamera.updateMatrixWorld(); + function getParameters( material, lights, shadows, scene, nClipPlanes, nClipIntersection, object ) { - // compute shadow matrix + var fog = scene.fog; + var environment = material.isMeshStandardMaterial ? scene.environment : null; - 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 - ); + var envMap = material.envMap || environment; - shadowMatrix.multiply( shadowCamera.projectionMatrix ); - shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); + var shaderID = shaderIDs[ material.type ]; - } + // heuristics to create shader parameters according to lights in the scene + // (not to blow over maxLights budget) - _renderer.setRenderTarget( shadowMap ); - _renderer.clear(); + var maxBones = object.isSkinnedMesh ? allocateBones( object ) : 0; - // render shadow map for each cube face (if omni-directional) or - // run a single pass if not + if ( material.precision !== null ) { - for ( var face = 0; face < faceCount; face ++ ) { + precision = capabilities.getMaxPrecision( material.precision ); - if ( isPointLight ) { + if ( precision !== material.precision ) { - _lookTarget.copy( shadowCamera.position ); - _lookTarget.add( cubeDirections[ face ] ); - shadowCamera.up.copy( cubeUps[ face ] ); - shadowCamera.lookAt( _lookTarget ); - shadowCamera.updateMatrixWorld(); + console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); - var vpDimensions = cube2DViewPorts[ face ]; - _state.viewport( vpDimensions ); + } - } + } - // update camera matrices and frustum + var vertexShader, fragmentShader; - _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + if ( shaderID ) { - // set object matrices & frustum culling + var shader = ShaderLib[ shaderID ]; - renderObject( scene, camera, shadowCamera, isPointLight ); + vertexShader = shader.vertexShader; + fragmentShader = shader.fragmentShader; - } + } else { - } + vertexShader = material.vertexShader; + fragmentShader = material.fragmentShader; - scope.needsUpdate = false; + } - }; + var currentRenderTarget = renderer.getRenderTarget(); - function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) { + var parameters = { - var geometry = object.geometry; + isWebGL2: isWebGL2, - var result = null; + shaderID: shaderID, + shaderName: material.type, - var materialVariants = _depthMaterials; - var customMaterial = object.customDepthMaterial; + vertexShader: vertexShader, + fragmentShader: fragmentShader, + defines: material.defines, - if ( isPointLight ) { + isRawShaderMaterial: material.isRawShaderMaterial, + isShaderMaterial: material.isShaderMaterial, - materialVariants = _distanceMaterials; - customMaterial = object.customDistanceMaterial; + precision: precision, - } + instancing: object.isInstancedMesh === true, - if ( ! customMaterial ) { + 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, + clearcoatMap: !! material.clearcoatMap, + clearcoatRoughnessMap: !! material.clearcoatRoughnessMap, + clearcoatNormalMap: !! material.clearcoatNormalMap, + displacementMap: !! material.displacementMap, + roughnessMap: !! material.roughnessMap, + metalnessMap: !! material.metalnessMap, + specularMap: !! material.specularMap, + alphaMap: !! material.alphaMap, - var useMorphing = false; + gradientMap: !! material.gradientMap, - if ( material.morphTargets ) { + sheen: !! material.sheen, - if ( geometry && geometry.isBufferGeometry ) { + transmissionMap: !! material.transmissionMap, - useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0; + combine: material.combine, - } else if ( geometry && geometry.isGeometry ) { + vertexTangents: ( material.normalMap && material.vertexTangents ), + vertexColors: material.vertexColors, + 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, + uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.transmissionMap ) && !! material.displacementMap, - useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0; + fog: !! fog, + useFog: material.fog, + fogExp2: ( fog && fog.isFogExp2 ), - } + flatShading: material.flatShading, - } + sizeAttenuation: material.sizeAttenuation, + logarithmicDepthBuffer: logarithmicDepthBuffer, - if ( object.isSkinnedMesh && material.skinning === false ) { + skinning: material.skinning && maxBones > 0, + maxBones: maxBones, + useVertexTexture: floatVertexTextures, - console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object ); + morphTargets: material.morphTargets, + morphNormals: material.morphNormals, + maxMorphTargets: renderer.maxMorphTargets, + maxMorphNormals: renderer.maxMorphNormals, - } + numDirLights: lights.directional.length, + numPointLights: lights.point.length, + numSpotLights: lights.spot.length, + numRectAreaLights: lights.rectArea.length, + numHemiLights: lights.hemi.length, - var useSkinning = object.isSkinnedMesh && material.skinning; + numDirLightShadows: lights.directionalShadowMap.length, + numPointLightShadows: lights.pointShadowMap.length, + numSpotLightShadows: lights.spotShadowMap.length, - var variantIndex = 0; + numClippingPlanes: nClipPlanes, + numClipIntersection: nClipIntersection, - if ( useMorphing ) variantIndex |= _MorphingFlag; - if ( useSkinning ) variantIndex |= _SkinningFlag; + dithering: material.dithering, - result = materialVariants[ variantIndex ]; + shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, + shadowMapType: renderer.shadowMap.type, - } else { + toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping, + physicallyCorrectLights: renderer.physicallyCorrectLights, - result = customMaterial; + premultipliedAlpha: material.premultipliedAlpha, - } + alphaTest: material.alphaTest, + doubleSided: material.side === DoubleSide, + flipSided: material.side === BackSide, - if ( _renderer.localClippingEnabled && - material.clipShadows === true && - material.clippingPlanes.length !== 0 ) { + depthPacking: ( material.depthPacking !== undefined ) ? material.depthPacking : false, - // in this case we need a unique material instance reflecting the - // appropriate state + index0AttributeName: material.index0AttributeName, - var keyA = result.uuid, keyB = material.uuid; + extensionDerivatives: material.extensions && material.extensions.derivatives, + extensionFragDepth: material.extensions && material.extensions.fragDepth, + extensionDrawBuffers: material.extensions && material.extensions.drawBuffers, + extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD, - var materialsForVariant = _materialCache[ keyA ]; + rendererExtensionFragDepth: isWebGL2 || extensions.get( 'EXT_frag_depth' ) !== null, + rendererExtensionDrawBuffers: isWebGL2 || extensions.get( 'WEBGL_draw_buffers' ) !== null, + rendererExtensionShaderTextureLod: isWebGL2 || extensions.get( 'EXT_shader_texture_lod' ) !== null, - if ( materialsForVariant === undefined ) { + customProgramCacheKey: material.customProgramCacheKey() - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; + }; - } + return parameters; - var cachedMaterial = materialsForVariant[ keyB ]; + } - if ( cachedMaterial === undefined ) { + function getProgramCacheKey( parameters ) { - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; + var array = []; - } + if ( parameters.shaderID ) { - result = cachedMaterial; + array.push( parameters.shaderID ); - } + } else { - result.visible = material.visible; - result.wireframe = material.wireframe; + array.push( parameters.fragmentShader ); + array.push( parameters.vertexShader ); - result.side = ( material.shadowSide != null ) ? material.shadowSide : shadowSide[ material.side ]; + } - result.clipShadows = material.clipShadows; - result.clippingPlanes = material.clippingPlanes; - result.clipIntersection = material.clipIntersection; + if ( parameters.defines !== undefined ) { - result.wireframeLinewidth = material.wireframeLinewidth; - result.linewidth = material.linewidth; + for ( var name in parameters.defines ) { - if ( isPointLight && result.isMeshDistanceMaterial ) { + array.push( name ); + array.push( parameters.defines[ name ] ); - result.referencePosition.copy( lightPositionWorld ); - result.nearDistance = shadowCameraNear; - result.farDistance = shadowCameraFar; + } } - return result; + if ( parameters.isRawShaderMaterial === undefined ) { - } + for ( var i = 0; i < parameterNames.length; i ++ ) { - function renderObject( object, camera, shadowCamera, isPointLight ) { + array.push( parameters[ parameterNames[ i ] ] ); - if ( object.visible === false ) return; + } - var visible = object.layers.test( camera.layers ); + array.push( renderer.outputEncoding ); + array.push( renderer.gammaFactor ); - if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { + } - if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { + array.push( parameters.customProgramCacheKey ); - object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); + return array.join(); - var geometry = _objects.update( object ); - var material = object.material; + } - if ( Array.isArray( material ) ) { + function getUniforms( material ) { - var groups = geometry.groups; + var shaderID = shaderIDs[ material.type ]; + var uniforms; - for ( var k = 0, kl = groups.length; k < kl; k ++ ) { + if ( shaderID ) { - var group = groups[ k ]; - var groupMaterial = material[ group.materialIndex ]; + var shader = ShaderLib[ shaderID ]; + uniforms = UniformsUtils.clone( shader.uniforms ); - if ( groupMaterial && groupMaterial.visible ) { + } else { - var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + uniforms = material.uniforms; - } + } - } + return uniforms; - } else if ( material.visible ) { + } - var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far ); - _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); + function acquireProgram( parameters, cacheKey ) { - } + var program; - } + // Check if code has been already compiled + for ( var p = 0, pl = programs.length; p < pl; p ++ ) { - } + var preexistingProgram = programs[ p ]; - var children = object.children; + if ( preexistingProgram.cacheKey === cacheKey ) { - for ( var i = 0, l = children.length; i < l; i ++ ) { + program = preexistingProgram; + ++ program.usedTimes; - renderObject( children[ i ], camera, shadowCamera, isPointLight ); + break; + + } } - } + if ( program === undefined ) { - } + program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates ); + programs.push( program ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function WebGLState( gl, extensions, utils, capabilities ) { + return program; - function ColorBuffer() { + } - var locked = false; + function releaseProgram( program ) { - var color = new Vector4(); - var currentColorMask = null; - var currentColorClear = new Vector4( 0, 0, 0, 0 ); + if ( -- program.usedTimes === 0 ) { - return { + // Remove from unordered set + var i = programs.indexOf( program ); + programs[ i ] = programs[ programs.length - 1 ]; + programs.pop(); - setMask: function ( colorMask ) { + // Free WebGL resources + program.destroy(); - if ( currentColorMask !== colorMask && ! locked ) { + } - gl.colorMask( colorMask, colorMask, colorMask, colorMask ); - currentColorMask = colorMask; + } - } + return { + getParameters: getParameters, + getProgramCacheKey: getProgramCacheKey, + getUniforms: getUniforms, + acquireProgram: acquireProgram, + releaseProgram: releaseProgram, + // Exposed for resource monitoring & error feedback via renderer.info: + programs: programs + }; - }, + } - setLocked: function ( lock ) { + function WebGLProperties() { - locked = lock; + var properties = new WeakMap(); - }, + function get( object ) { - setClear: function ( r, g, b, a, premultipliedAlpha ) { + var map = properties.get( object ); - if ( premultipliedAlpha === true ) { + if ( map === undefined ) { - r *= a; g *= a; b *= a; + map = {}; + properties.set( object, map ); - } + } - color.set( r, g, b, a ); + return map; - if ( currentColorClear.equals( color ) === false ) { + } - gl.clearColor( r, g, b, a ); - currentColorClear.copy( color ); + function remove( object ) { - } + properties.delete( object ); - }, + } - reset: function () { + function update( object, key, value ) { - locked = false; + properties.get( object )[ key ] = value; - currentColorMask = null; - currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state + } - } + function dispose() { - }; + properties = new WeakMap(); } - function DepthBuffer() { + return { + get: get, + remove: remove, + update: update, + dispose: dispose + }; - var locked = false; + } - var currentDepthMask = null; - var currentDepthFunc = null; - var currentDepthClear = null; + function painterSortStable( a, b ) { - return { + if ( a.groupOrder !== b.groupOrder ) { - setTest: function ( depthTest ) { + return a.groupOrder - b.groupOrder; - if ( depthTest ) { + } else if ( a.renderOrder !== b.renderOrder ) { - enable( 2929 ); + return a.renderOrder - b.renderOrder; - } else { + } else if ( a.program !== b.program ) { - disable( 2929 ); + return a.program.id - b.program.id; - } + } else if ( a.material.id !== b.material.id ) { - }, + return a.material.id - b.material.id; - setMask: function ( depthMask ) { + } else if ( a.z !== b.z ) { - if ( currentDepthMask !== depthMask && ! locked ) { + return a.z - b.z; - gl.depthMask( depthMask ); - currentDepthMask = depthMask; + } else { - } + return a.id - b.id; - }, + } - setFunc: function ( depthFunc ) { + } - if ( currentDepthFunc !== depthFunc ) { + function reversePainterSortStable( a, b ) { - if ( depthFunc ) { + if ( a.groupOrder !== b.groupOrder ) { - switch ( depthFunc ) { + return a.groupOrder - b.groupOrder; - case NeverDepth: + } else if ( a.renderOrder !== b.renderOrder ) { - gl.depthFunc( 512 ); - break; + return a.renderOrder - b.renderOrder; - case AlwaysDepth: + } else if ( a.z !== b.z ) { - gl.depthFunc( 519 ); - break; + return b.z - a.z; - case LessDepth: + } else { - gl.depthFunc( 513 ); - break; + return a.id - b.id; - case LessEqualDepth: + } - gl.depthFunc( 515 ); - break; + } - case EqualDepth: - gl.depthFunc( 514 ); - break; + function WebGLRenderList( properties ) { - case GreaterEqualDepth: + var renderItems = []; + var renderItemsIndex = 0; - gl.depthFunc( 518 ); - break; + var opaque = []; + var transparent = []; - case GreaterDepth: + var defaultProgram = { id: - 1 }; - gl.depthFunc( 516 ); - break; + function init() { - case NotEqualDepth: + renderItemsIndex = 0; - gl.depthFunc( 517 ); - break; + opaque.length = 0; + transparent.length = 0; - default: + } - gl.depthFunc( 515 ); + function getNextRenderItem( object, geometry, material, groupOrder, z, group ) { - } + var renderItem = renderItems[ renderItemsIndex ]; + var materialProperties = properties.get( material ); - } else { + if ( renderItem === undefined ) { - gl.depthFunc( 515 ); + 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; - currentDepthFunc = depthFunc; + } 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; - }, + } - setLocked: function ( lock ) { + renderItemsIndex ++; - locked = lock; + return renderItem; - }, + } - setClear: function ( depth ) { + function push( object, geometry, material, groupOrder, z, group ) { - if ( currentDepthClear !== depth ) { + var renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - gl.clearDepth( depth ); - currentDepthClear = depth; + ( material.transparent === true ? transparent : opaque ).push( renderItem ); - } + } - }, + function unshift( object, geometry, material, groupOrder, z, group ) { - reset: function () { + var renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); - locked = false; + ( material.transparent === true ? transparent : opaque ).unshift( renderItem ); - currentDepthMask = null; - currentDepthFunc = null; - currentDepthClear = null; + } - } + function sort( customOpaqueSort, customTransparentSort ) { - }; + if ( opaque.length > 1 ) { opaque.sort( customOpaqueSort || painterSortStable ); } + if ( transparent.length > 1 ) { transparent.sort( customTransparentSort || reversePainterSortStable ); } } - function StencilBuffer() { + function finish() { - var locked = false; + // Clear references from inactive renderItems in the list - var currentStencilMask = null; - var currentStencilFunc = null; - var currentStencilRef = null; - var currentStencilFuncMask = null; - var currentStencilFail = null; - var currentStencilZFail = null; - var currentStencilZPass = null; - var currentStencilClear = null; + for ( var i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) { - return { + var renderItem = renderItems[ i ]; - setTest: function ( stencilTest ) { + if ( renderItem.id === null ) { break; } - if ( stencilTest ) { + renderItem.id = null; + renderItem.object = null; + renderItem.geometry = null; + renderItem.material = null; + renderItem.program = null; + renderItem.group = null; - enable( 2960 ); + } - } else { + } - disable( 2960 ); + return { - } + opaque: opaque, + transparent: transparent, - }, + init: init, + push: push, + unshift: unshift, + finish: finish, - setMask: function ( stencilMask ) { + sort: sort + }; - if ( currentStencilMask !== stencilMask && ! locked ) { + } - gl.stencilMask( stencilMask ); - currentStencilMask = stencilMask; + function WebGLRenderLists( properties ) { - } + var lists = new WeakMap(); - }, + function onSceneDispose( event ) { - setFunc: function ( stencilFunc, stencilRef, stencilMask ) { + var scene = event.target; - if ( currentStencilFunc !== stencilFunc || - currentStencilRef !== stencilRef || - currentStencilFuncMask !== stencilMask ) { + scene.removeEventListener( 'dispose', onSceneDispose ); - gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); + lists.delete( scene ); - currentStencilFunc = stencilFunc; - currentStencilRef = stencilRef; - currentStencilFuncMask = stencilMask; + } - } + function get( scene, camera ) { - }, + var cameras = lists.get( scene ); + var list; - setOp: function ( stencilFail, stencilZFail, stencilZPass ) { + if ( cameras === undefined ) { - if ( currentStencilFail !== stencilFail || - currentStencilZFail !== stencilZFail || - currentStencilZPass !== stencilZPass ) { + list = new WebGLRenderList( properties ); + lists.set( scene, new WeakMap() ); + lists.get( scene ).set( camera, list ); - gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); + scene.addEventListener( 'dispose', onSceneDispose ); - currentStencilFail = stencilFail; - currentStencilZFail = stencilZFail; - currentStencilZPass = stencilZPass; + } else { - } + list = cameras.get( camera ); + if ( list === undefined ) { - }, + list = new WebGLRenderList( properties ); + cameras.set( camera, list ); - setLocked: function ( lock ) { + } - locked = lock; + } - }, + return list; - setClear: function ( stencil ) { + } - if ( currentStencilClear !== stencil ) { + function dispose() { - gl.clearStencil( stencil ); - currentStencilClear = stencil; + lists = new WeakMap(); - } + } - }, + return { + get: get, + dispose: dispose + }; - reset: function () { + } - locked = false; + function UniformsCache() { - currentStencilMask = null; - currentStencilFunc = null; - currentStencilRef = null; - currentStencilFuncMask = null; - currentStencilFail = null; - currentStencilZFail = null; - currentStencilZPass = null; - currentStencilClear = null; + var lights = {}; - } + return { - }; + get: function ( light ) { - } + if ( lights[ light.id ] !== undefined ) { - // + return lights[ light.id ]; - var colorBuffer = new ColorBuffer(); - var depthBuffer = new DepthBuffer(); - var stencilBuffer = new StencilBuffer(); + } - var maxVertexAttributes = gl.getParameter( 34921 ); - var newAttributes = new Uint8Array( maxVertexAttributes ); - var enabledAttributes = new Uint8Array( maxVertexAttributes ); - var attributeDivisors = new Uint8Array( maxVertexAttributes ); + var uniforms; - var enabledCapabilities = {}; + switch ( light.type ) { - var compressedTextureFormats = null; + case 'DirectionalLight': + uniforms = { + direction: new Vector3(), + color: new Color() + }; + break; - var currentProgram = null; + case 'SpotLight': + uniforms = { + position: new Vector3(), + direction: new Vector3(), + color: new Color(), + distance: 0, + coneCos: 0, + penumbraCos: 0, + decay: 0 + }; + break; - var currentBlendingEnabled = null; - var currentBlending = null; - var currentBlendEquation = null; - var currentBlendSrc = null; - var currentBlendDst = null; - var currentBlendEquationAlpha = null; - var currentBlendSrcAlpha = null; - var currentBlendDstAlpha = null; - var currentPremultipledAlpha = false; + case 'PointLight': + uniforms = { + position: new Vector3(), + color: new Color(), + distance: 0, + decay: 0 + }; + break; - var currentFlipSided = null; - var currentCullFace = null; + case 'HemisphereLight': + uniforms = { + direction: new Vector3(), + skyColor: new Color(), + groundColor: new Color() + }; + break; - var currentLineWidth = null; + case 'RectAreaLight': + uniforms = { + color: new Color(), + position: new Vector3(), + halfWidth: new Vector3(), + halfHeight: new Vector3() + }; + break; - var currentPolygonOffsetFactor = null; - var currentPolygonOffsetUnits = null; + } - var maxTextures = gl.getParameter( 35661 ); + lights[ light.id ] = uniforms; - var lineWidthAvailable = false; - var version = 0; - var glVersion = gl.getParameter( 7938 ); + return uniforms; - if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { + } - version = parseFloat( /^WebGL\ ([0-9])/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 1.0 ); + }; - } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) { + } - version = parseFloat( /^OpenGL\ ES\ ([0-9])/.exec( glVersion )[ 1 ] ); - lineWidthAvailable = ( version >= 2.0 ); + function ShadowUniformsCache() { - } + var lights = {}; - var currentTextureSlot = null; - var currentBoundTextures = {}; + return { - var currentScissor = new Vector4(); - var currentViewport = new Vector4(); + get: function ( light ) { - function createTexture( type, target, count ) { + if ( lights[ light.id ] !== undefined ) { - var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. - var texture = gl.createTexture(); + return lights[ light.id ]; - gl.bindTexture( type, texture ); - gl.texParameteri( type, 10241, 9728 ); - gl.texParameteri( type, 10240, 9728 ); + } - for ( var i = 0; i < count; i ++ ) { + var uniforms; - gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); + switch ( light.type ) { - } + case 'DirectionalLight': + uniforms = { + shadowBias: 0, + shadowNormalBias: 0, + shadowRadius: 1, + shadowMapSize: new Vector2() + }; + break; - return texture; + 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; - var emptyTextures = {}; - emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); - emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); + // TODO (abelnation): set RectAreaLight shadow uniforms - // init + } - colorBuffer.setClear( 0, 0, 0, 1 ); - depthBuffer.setClear( 1 ); - stencilBuffer.setClear( 0 ); + lights[ light.id ] = uniforms; - enable( 2929 ); - depthBuffer.setFunc( LessEqualDepth ); + return uniforms; - setFlipSided( false ); - setCullFace( CullFaceBack ); - enable( 2884 ); + } - setBlending( NoBlending ); + }; - // + } - function initAttributes() { - for ( var i = 0, l = newAttributes.length; i < l; i ++ ) { - newAttributes[ i ] = 0; + var nextVersion = 0; - } + function shadowCastingLightsFirst( lightA, lightB ) { - } + return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 ); - function enableAttribute( attribute ) { + } - enableAttributeAndDivisor( attribute, 0 ); + function WebGLLights() { - } + var cache = new UniformsCache(); - function enableAttributeAndDivisor( attribute, meshPerAttribute ) { + var shadowCache = ShadowUniformsCache(); - newAttributes[ attribute ] = 1; + var state = { - if ( enabledAttributes[ attribute ] === 0 ) { + version: 0, - gl.enableVertexAttribArray( attribute ); - enabledAttributes[ attribute ] = 1; + hash: { + directionalLength: - 1, + pointLength: - 1, + spotLength: - 1, + rectAreaLength: - 1, + hemiLength: - 1, - } + numDirectionalShadows: - 1, + numPointShadows: - 1, + numSpotShadows: - 1 + }, - if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { + ambient: [ 0, 0, 0 ], + probe: [], + directional: [], + directionalShadow: [], + directionalShadowMap: [], + directionalShadowMatrix: [], + spot: [], + spotShadow: [], + spotShadowMap: [], + spotShadowMatrix: [], + rectArea: [], + point: [], + pointShadow: [], + pointShadowMap: [], + pointShadowMatrix: [], + hemi: [] - var extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); + }; - extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); - attributeDivisors[ attribute ] = meshPerAttribute; + for ( var i = 0; i < 9; i ++ ) { state.probe.push( new Vector3() ); } - } + var vector3 = new Vector3(); + var matrix4 = new Matrix4(); + var matrix42 = new Matrix4(); - } + function setup( lights, shadows, camera ) { - function disableUnusedAttributes() { + var r = 0, g = 0, b = 0; - for ( var i = 0, l = enabledAttributes.length; i !== l; ++ i ) { + for ( var i = 0; i < 9; i ++ ) { state.probe[ i ].set( 0, 0, 0 ); } - if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { + var directionalLength = 0; + var pointLength = 0; + var spotLength = 0; + var rectAreaLength = 0; + var hemiLength = 0; - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; + var numDirectionalShadows = 0; + var numPointShadows = 0; + var numSpotShadows = 0; - } + var viewMatrix = camera.matrixWorldInverse; - } + lights.sort( shadowCastingLightsFirst ); - } + for ( var i$1 = 0, l = lights.length; i$1 < l; i$1 ++ ) { - function enable( id ) { + var light = lights[ i$1 ]; - if ( enabledCapabilities[ id ] !== true ) { + var color = light.color; + var intensity = light.intensity; + var distance = light.distance; - gl.enable( id ); - enabledCapabilities[ id ] = true; + var shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; - } + if ( light.isAmbientLight ) { - } + r += color.r * intensity; + g += color.g * intensity; + b += color.b * intensity; - function disable( id ) { + } else if ( light.isLightProbe ) { - if ( enabledCapabilities[ id ] !== false ) { + for ( var j = 0; j < 9; j ++ ) { - gl.disable( id ); - enabledCapabilities[ id ] = false; + state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity ); - } + } - } + } else if ( light.isDirectionalLight ) { + + var uniforms = cache.get( light ); - function getCompressedTextureFormats() { + uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); + uniforms.direction.setFromMatrixPosition( light.matrixWorld ); + vector3.setFromMatrixPosition( light.target.matrixWorld ); + uniforms.direction.sub( vector3 ); + uniforms.direction.transformDirection( viewMatrix ); - if ( compressedTextureFormats === null ) { + if ( light.castShadow ) { - compressedTextureFormats = []; + var shadow = light.shadow; - if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || - extensions.get( 'WEBGL_compressed_texture_s3tc' ) || - extensions.get( 'WEBGL_compressed_texture_etc1' ) || - extensions.get( 'WEBGL_compressed_texture_astc' ) ) { + var shadowUniforms = shadowCache.get( light ); - var formats = gl.getParameter( 34467 ); + shadowUniforms.shadowBias = shadow.bias; + shadowUniforms.shadowNormalBias = shadow.normalBias; + shadowUniforms.shadowRadius = shadow.radius; + shadowUniforms.shadowMapSize = shadow.mapSize; - for ( var i = 0; i < formats.length; i ++ ) { + state.directionalShadow[ directionalLength ] = shadowUniforms; + state.directionalShadowMap[ directionalLength ] = shadowMap; + state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; - compressedTextureFormats.push( formats[ i ] ); + numDirectionalShadows ++; } - } + state.directional[ directionalLength ] = uniforms; - } + directionalLength ++; - return compressedTextureFormats; + } else if ( light.isSpotLight ) { - } + var uniforms$1 = cache.get( light ); - function useProgram( program ) { + uniforms$1.position.setFromMatrixPosition( light.matrixWorld ); + uniforms$1.position.applyMatrix4( viewMatrix ); - if ( currentProgram !== program ) { + uniforms$1.color.copy( color ).multiplyScalar( intensity ); + uniforms$1.distance = distance; - gl.useProgram( program ); + uniforms$1.direction.setFromMatrixPosition( light.matrixWorld ); + vector3.setFromMatrixPosition( light.target.matrixWorld ); + uniforms$1.direction.sub( vector3 ); + uniforms$1.direction.transformDirection( viewMatrix ); - currentProgram = program; + uniforms$1.coneCos = Math.cos( light.angle ); + uniforms$1.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); + uniforms$1.decay = light.decay; - return true; + if ( light.castShadow ) { - } + var shadow$1 = light.shadow; - return false; + var shadowUniforms$1 = shadowCache.get( light ); - } + shadowUniforms$1.shadowBias = shadow$1.bias; + shadowUniforms$1.shadowNormalBias = shadow$1.normalBias; + shadowUniforms$1.shadowRadius = shadow$1.radius; + shadowUniforms$1.shadowMapSize = shadow$1.mapSize; - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + state.spotShadow[ spotLength ] = shadowUniforms$1; + state.spotShadowMap[ spotLength ] = shadowMap; + state.spotShadowMatrix[ spotLength ] = light.shadow.matrix; - if ( blending === NoBlending ) { + numSpotShadows ++; - if ( currentBlendingEnabled ) { + } - disable( 3042 ); - currentBlendingEnabled = false; + state.spot[ spotLength ] = uniforms$1; - } + spotLength ++; - return; + } else if ( light.isRectAreaLight ) { - } + var uniforms$2 = cache.get( light ); - if ( ! currentBlendingEnabled ) { + // (a) intensity is the total visible light emitted + //uniforms.color.copy( color ).multiplyScalar( intensity / ( light.width * light.height * Math.PI ) ); - enable( 3042 ); - currentBlendingEnabled = true; + // (b) intensity is the brightness of the light + uniforms$2.color.copy( color ).multiplyScalar( intensity ); - } + uniforms$2.position.setFromMatrixPosition( light.matrixWorld ); + uniforms$2.position.applyMatrix4( viewMatrix ); - if ( blending !== CustomBlending ) { + // extract local rotation of light to derive width/height half vectors + matrix42.identity(); + matrix4.copy( light.matrixWorld ); + matrix4.premultiply( viewMatrix ); + matrix42.extractRotation( matrix4 ); - if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { + uniforms$2.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); + uniforms$2.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); - if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { + uniforms$2.halfWidth.applyMatrix4( matrix42 ); + uniforms$2.halfHeight.applyMatrix4( matrix42 ); - gl.blendEquation( 32774 ); + // TODO (abelnation): RectAreaLight distance? + // uniforms.distance = distance; - currentBlendEquation = AddEquation; - currentBlendEquationAlpha = AddEquation; + state.rectArea[ rectAreaLength ] = uniforms$2; - } + rectAreaLength ++; - if ( premultipliedAlpha ) { + } else if ( light.isPointLight ) { - switch ( blending ) { + var uniforms$3 = cache.get( light ); - case NormalBlending: - gl.blendFuncSeparate( 1, 771, 1, 771 ); - break; + uniforms$3.position.setFromMatrixPosition( light.matrixWorld ); + uniforms$3.position.applyMatrix4( viewMatrix ); - case AdditiveBlending: - gl.blendFunc( 1, 1 ); - break; + uniforms$3.color.copy( light.color ).multiplyScalar( light.intensity ); + uniforms$3.distance = light.distance; + uniforms$3.decay = light.decay; - case SubtractiveBlending: - gl.blendFuncSeparate( 0, 0, 769, 771 ); - break; + if ( light.castShadow ) { - case MultiplyBlending: - gl.blendFuncSeparate( 0, 768, 0, 770 ); - break; + var shadow$2 = light.shadow; - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; + var shadowUniforms$2 = shadowCache.get( light ); - } + shadowUniforms$2.shadowBias = shadow$2.bias; + shadowUniforms$2.shadowNormalBias = shadow$2.normalBias; + shadowUniforms$2.shadowRadius = shadow$2.radius; + shadowUniforms$2.shadowMapSize = shadow$2.mapSize; + shadowUniforms$2.shadowCameraNear = shadow$2.camera.near; + shadowUniforms$2.shadowCameraFar = shadow$2.camera.far; - } else { + state.pointShadow[ pointLength ] = shadowUniforms$2; + state.pointShadowMap[ pointLength ] = shadowMap; + state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; - switch ( blending ) { + numPointShadows ++; - case NormalBlending: - gl.blendFuncSeparate( 770, 771, 1, 771 ); - break; + } - case AdditiveBlending: - gl.blendFunc( 770, 1 ); - break; + state.point[ pointLength ] = uniforms$3; - case SubtractiveBlending: - gl.blendFunc( 0, 769 ); - break; + pointLength ++; - case MultiplyBlending: - gl.blendFunc( 0, 768 ); - break; + } else if ( light.isHemisphereLight ) { - default: - console.error( 'THREE.WebGLState: Invalid blending: ', blending ); - break; + var uniforms$4 = cache.get( light ); - } + uniforms$4.direction.setFromMatrixPosition( light.matrixWorld ); + uniforms$4.direction.transformDirection( viewMatrix ); + uniforms$4.direction.normalize(); - } + uniforms$4.skyColor.copy( light.color ).multiplyScalar( intensity ); + uniforms$4.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); - currentBlendSrc = null; - currentBlendDst = null; - currentBlendSrcAlpha = null; - currentBlendDstAlpha = null; + state.hemi[ hemiLength ] = uniforms$4; - currentBlending = blending; - currentPremultipledAlpha = premultipliedAlpha; + hemiLength ++; } - return; - } - // custom blending - - blendEquationAlpha = blendEquationAlpha || blendEquation; - blendSrcAlpha = blendSrcAlpha || blendSrc; - blendDstAlpha = blendDstAlpha || blendDst; + state.ambient[ 0 ] = r; + state.ambient[ 1 ] = g; + state.ambient[ 2 ] = b; - if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { + var hash = state.hash; - gl.blendEquationSeparate( utils.convert( blendEquation ), utils.convert( blendEquationAlpha ) ); + 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 ) { - currentBlendEquation = blendEquation; - currentBlendEquationAlpha = blendEquationAlpha; + 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; - if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { + hash.directionalLength = directionalLength; + hash.pointLength = pointLength; + hash.spotLength = spotLength; + hash.rectAreaLength = rectAreaLength; + hash.hemiLength = hemiLength; - gl.blendFuncSeparate( utils.convert( blendSrc ), utils.convert( blendDst ), utils.convert( blendSrcAlpha ), utils.convert( blendDstAlpha ) ); + hash.numDirectionalShadows = numDirectionalShadows; + hash.numPointShadows = numPointShadows; + hash.numSpotShadows = numSpotShadows; - currentBlendSrc = blendSrc; - currentBlendDst = blendDst; - currentBlendSrcAlpha = blendSrcAlpha; - currentBlendDstAlpha = blendDstAlpha; + state.version = nextVersion ++; } - currentBlending = blending; - currentPremultipledAlpha = null; - } - function setMaterial( material, frontFaceCW ) { + return { + setup: setup, + state: state + }; - material.side === DoubleSide - ? disable( 2884 ) - : enable( 2884 ); + } - var flipSided = ( material.side === BackSide ); - if ( frontFaceCW ) flipSided = ! flipSided; + function WebGLRenderState() { - setFlipSided( flipSided ); + var lights = new WebGLLights(); - ( 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 ); + var lightsArray = []; + var shadowsArray = []; - depthBuffer.setFunc( material.depthFunc ); - depthBuffer.setTest( material.depthTest ); - depthBuffer.setMask( material.depthWrite ); - colorBuffer.setMask( material.colorWrite ); + function init() { - setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); + lightsArray.length = 0; + shadowsArray.length = 0; } - // + function pushLight( light ) { - function setFlipSided( flipSided ) { + lightsArray.push( light ); - if ( currentFlipSided !== flipSided ) { + } - if ( flipSided ) { + function pushShadow( shadowLight ) { - gl.frontFace( 2304 ); + shadowsArray.push( shadowLight ); - } else { + } - gl.frontFace( 2305 ); + function setupLights( camera ) { - } + lights.setup( lightsArray, shadowsArray, camera ); - currentFlipSided = flipSided; + } - } + var state = { + lightsArray: lightsArray, + shadowsArray: shadowsArray, - } + lights: lights + }; - function setCullFace( cullFace ) { + return { + init: init, + state: state, + setupLights: setupLights, - if ( cullFace !== CullFaceNone ) { + pushLight: pushLight, + pushShadow: pushShadow + }; - enable( 2884 ); + } - if ( cullFace !== currentCullFace ) { + function WebGLRenderStates() { - if ( cullFace === CullFaceBack ) { + var renderStates = new WeakMap(); - gl.cullFace( 1029 ); + function onSceneDispose( event ) { - } else if ( cullFace === CullFaceFront ) { + var scene = event.target; - gl.cullFace( 1028 ); + scene.removeEventListener( 'dispose', onSceneDispose ); - } else { + renderStates.delete( scene ); - gl.cullFace( 1032 ); + } - } + function get( scene, camera ) { - } + var renderState; - } else { + if ( renderStates.has( scene ) === false ) { - disable( 2884 ); + renderState = new WebGLRenderState(); + renderStates.set( scene, new WeakMap() ); + renderStates.get( scene ).set( camera, renderState ); - } + scene.addEventListener( 'dispose', onSceneDispose ); - currentCullFace = cullFace; + } else { - } + if ( renderStates.get( scene ).has( camera ) === false ) { - function setLineWidth( width ) { + renderState = new WebGLRenderState(); + renderStates.get( scene ).set( camera, renderState ); - if ( width !== currentLineWidth ) { + } else { - if ( lineWidthAvailable ) gl.lineWidth( width ); + renderState = renderStates.get( scene ).get( camera ); - currentLineWidth = width; + } } - } + return renderState; - function setPolygonOffset( polygonOffset, factor, units ) { + } - if ( polygonOffset ) { + function dispose() { - enable( 32823 ); + renderStates = new WeakMap(); - if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { + } - gl.polygonOffset( factor, units ); + return { + get: get, + dispose: dispose + }; - currentPolygonOffsetFactor = factor; - currentPolygonOffsetUnits = units; + } - } + /** + * parameters = { + * + * opacity: , + * + * map: new THREE.Texture( ), + * + * alphaMap: new THREE.Texture( ), + * + * displacementMap: new THREE.Texture( ), + * displacementScale: , + * displacementBias: , + * + * wireframe: , + * wireframeLinewidth: + * } + */ - } else { + function MeshDepthMaterial( parameters ) { - disable( 32823 ); + Material.call( this ); - } + this.type = 'MeshDepthMaterial'; - } + this.depthPacking = BasicDepthPacking; - function setScissorTest( scissorTest ) { + this.skinning = false; + this.morphTargets = false; - if ( scissorTest ) { + this.map = null; - enable( 3089 ); + this.alphaMap = null; - } else { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - disable( 3089 ); + this.wireframe = false; + this.wireframeLinewidth = 1; - } + this.fog = false; - } + this.setValues( parameters ); - // texture + } - function activeTexture( webglSlot ) { + MeshDepthMaterial.prototype = Object.create( Material.prototype ); + MeshDepthMaterial.prototype.constructor = MeshDepthMaterial; - if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1; + MeshDepthMaterial.prototype.isMeshDepthMaterial = true; - if ( currentTextureSlot !== webglSlot ) { + MeshDepthMaterial.prototype.copy = function ( source ) { - gl.activeTexture( webglSlot ); - currentTextureSlot = webglSlot; + Material.prototype.copy.call( this, source ); - } + this.depthPacking = source.depthPacking; - } + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; - function bindTexture( webglType, webglTexture ) { + this.map = source.map; - if ( currentTextureSlot === null ) { + this.alphaMap = source.alphaMap; - activeTexture(); + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - } + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - var boundTexture = currentBoundTextures[ currentTextureSlot ]; + return this; - if ( boundTexture === undefined ) { + }; - boundTexture = { type: undefined, texture: undefined }; - currentBoundTextures[ currentTextureSlot ] = boundTexture; + /** + * parameters = { + * + * referencePosition: , + * nearDistance: , + * farDistance: , + * + * skinning: , + * morphTargets: , + * + * map: new THREE.Texture( ), + * + * alphaMap: new THREE.Texture( ), + * + * displacementMap: new THREE.Texture( ), + * displacementScale: , + * displacementBias: + * + * } + */ - } + function MeshDistanceMaterial( parameters ) { - if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { + Material.call( this ); - gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); + this.type = 'MeshDistanceMaterial'; - boundTexture.type = webglType; - boundTexture.texture = webglTexture; + this.referencePosition = new Vector3(); + this.nearDistance = 1; + this.farDistance = 1000; - } + this.skinning = false; + this.morphTargets = false; - } + this.map = null; - function compressedTexImage2D() { + this.alphaMap = null; - try { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - gl.compressedTexImage2D.apply( gl, arguments ); + this.fog = false; - } catch ( error ) { + this.setValues( parameters ); - console.error( 'THREE.WebGLState:', error ); + } - } + MeshDistanceMaterial.prototype = Object.create( Material.prototype ); + MeshDistanceMaterial.prototype.constructor = MeshDistanceMaterial; - } + MeshDistanceMaterial.prototype.isMeshDistanceMaterial = true; - function texImage2D() { + MeshDistanceMaterial.prototype.copy = function ( source ) { - try { + Material.prototype.copy.call( this, source ); - gl.texImage2D.apply( gl, arguments ); + this.referencePosition.copy( source.referencePosition ); + this.nearDistance = source.nearDistance; + this.farDistance = source.farDistance; - } catch ( error ) { + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; - console.error( 'THREE.WebGLState:', error ); + this.map = source.map; - } + this.alphaMap = source.alphaMap; - } + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - function texImage3D() { + return this; - try { + }; - gl.texImage3D.apply( gl, arguments ); + var vsm_frag = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include \nvoid main() {\n float mean = 0.0;\n float squared_mean = 0.0;\n\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy ) / resolution ) );\n for ( float i = -1.0; i < 1.0 ; i += SAMPLE_RATE) {\n #ifdef HORIZONAL_PASS\n vec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( i, 0.0 ) * radius ) / resolution ) );\n mean += distribution.x;\n squared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n #else\n float depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, i ) * radius ) / resolution ) );\n mean += depth;\n squared_mean += depth * depth;\n #endif\n }\n mean = mean * HALF_SAMPLE_RATE;\n squared_mean = squared_mean * HALF_SAMPLE_RATE;\n float std_dev = sqrt( squared_mean - mean * mean );\n gl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"; - } catch ( error ) { + var vsm_vert = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; - console.error( 'THREE.WebGLState:', error ); + function WebGLShadowMap( _renderer, _objects, maxTextureSize ) { - } + var _frustum = new Frustum(); - } + var _shadowMapSize = new Vector2(), + _viewportSize = new Vector2(), - // + _viewport = new Vector4(), - function scissor( scissor ) { + _depthMaterials = [], + _distanceMaterials = [], - if ( currentScissor.equals( scissor ) === false ) { + _materialCache = {}; - gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); - currentScissor.copy( scissor ); + var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; - } + var shadowMaterialVertical = new ShaderMaterial( { - } + defines: { + SAMPLE_RATE: 2.0 / 8.0, + HALF_SAMPLE_RATE: 1.0 / 8.0 + }, - function viewport( viewport ) { + uniforms: { + shadow_pass: { value: null }, + resolution: { value: new Vector2() }, + radius: { value: 4.0 } + }, - if ( currentViewport.equals( viewport ) === false ) { + vertexShader: vsm_vert, - gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); - currentViewport.copy( viewport ); + fragmentShader: vsm_frag - } + } ); - } + var shadowMaterialHorizonal = shadowMaterialVertical.clone(); + shadowMaterialHorizonal.defines.HORIZONAL_PASS = 1; - // + var fullScreenTri = new BufferGeometry(); + fullScreenTri.setAttribute( + "position", + new BufferAttribute( + new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ), + 3 + ) + ); - function reset() { + var fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical ); - for ( var i = 0; i < enabledAttributes.length; i ++ ) { + var scope = this; - if ( enabledAttributes[ i ] === 1 ) { + this.enabled = false; - gl.disableVertexAttribArray( i ); - enabledAttributes[ i ] = 0; + this.autoUpdate = true; + this.needsUpdate = false; - } + this.type = PCFShadowMap; - } + this.render = function ( lights, scene, camera ) { - enabledCapabilities = {}; + if ( scope.enabled === false ) { return; } + if ( scope.autoUpdate === false && scope.needsUpdate === false ) { return; } - compressedTextureFormats = null; + if ( lights.length === 0 ) { return; } - currentTextureSlot = null; - currentBoundTextures = {}; + var currentRenderTarget = _renderer.getRenderTarget(); + var activeCubeFace = _renderer.getActiveCubeFace(); + var activeMipmapLevel = _renderer.getActiveMipmapLevel(); - currentProgram = null; + var _state = _renderer.state; - currentBlending = null; + // 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 ); - currentFlipSided = null; - currentCullFace = null; + // render depth map - colorBuffer.reset(); - depthBuffer.reset(); - stencilBuffer.reset(); + for ( var i = 0, il = lights.length; i < il; i ++ ) { - } + var light = lights[ i ]; + var shadow = light.shadow; - return { + if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) { continue; } - buffers: { - color: colorBuffer, - depth: depthBuffer, - stencil: stencilBuffer - }, + if ( shadow === undefined ) { - initAttributes: initAttributes, - enableAttribute: enableAttribute, - enableAttributeAndDivisor: enableAttributeAndDivisor, - disableUnusedAttributes: disableUnusedAttributes, - enable: enable, - disable: disable, - getCompressedTextureFormats: getCompressedTextureFormats, + console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); + continue; - useProgram: useProgram, + } - setBlending: setBlending, - setMaterial: setMaterial, + _shadowMapSize.copy( shadow.mapSize ); - setFlipSided: setFlipSided, - setCullFace: setCullFace, + var shadowFrameExtents = shadow.getFrameExtents(); - setLineWidth: setLineWidth, - setPolygonOffset: setPolygonOffset, + _shadowMapSize.multiply( shadowFrameExtents ); - setScissorTest: setScissorTest, + _viewportSize.copy( shadow.mapSize ); - activeTexture: activeTexture, - bindTexture: bindTexture, - compressedTexImage2D: compressedTexImage2D, - texImage2D: texImage2D, - texImage3D: texImage3D, + if ( _shadowMapSize.x > maxTextureSize || _shadowMapSize.y > maxTextureSize ) { - scissor: scissor, - viewport: viewport, + if ( _shadowMapSize.x > maxTextureSize ) { - reset: reset + _viewportSize.x = Math.floor( maxTextureSize / shadowFrameExtents.x ); + _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; + shadow.mapSize.x = _viewportSize.x; - }; + } - } + if ( _shadowMapSize.y > maxTextureSize ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + _viewportSize.y = Math.floor( maxTextureSize / shadowFrameExtents.y ); + _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; + shadow.mapSize.y = _viewportSize.y; - function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { + } - var _videoTextures = {}; - var _canvas; + } - // + if ( shadow.map === null && ! shadow.isPointLightShadow && this.type === VSMShadowMap ) { - function clampToMaxSize( image, maxSize ) { + var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat, stencilBuffer: false }; - if ( image.width > maxSize || image.height > maxSize ) { + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); + shadow.map.texture.name = light.name + ".shadowMap"; - if ( 'data' in image ) { + shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); - console.warn( 'THREE.WebGLRenderer: image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); - return; + shadow.camera.updateProjectionMatrix(); } - // Warning: Scaling through the canvas will only work with images that use - // premultiplied alpha. + if ( shadow.map === null ) { + + var pars$1 = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat, stencilBuffer: false }; - var scale = maxSize / Math.max( image.width, image.height ); + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars$1 ); + shadow.map.texture.name = light.name + ".shadowMap"; - var canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - canvas.width = Math.floor( image.width * scale ); - canvas.height = Math.floor( image.height * scale ); + shadow.camera.updateProjectionMatrix(); - var context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height ); + } - console.warn( 'THREE.WebGLRenderer: image is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height ); + _renderer.setRenderTarget( shadow.map ); + _renderer.clear(); - return canvas; + var viewportCount = shadow.getViewportCount(); - } + for ( var vp = 0; vp < viewportCount; vp ++ ) { - return image; + var viewport = shadow.getViewport( vp ); - } + _viewport.set( + _viewportSize.x * viewport.x, + _viewportSize.y * viewport.y, + _viewportSize.x * viewport.z, + _viewportSize.y * viewport.w + ); - function isPowerOfTwo( image ) { + _state.viewport( _viewport ); - return _Math.isPowerOfTwo( image.width ) && _Math.isPowerOfTwo( image.height ); + shadow.updateMatrices( light, vp ); - } + _frustum = shadow.getFrustum(); - function makePowerOfTwo( image ) { + renderObject( scene, camera, shadow.camera, light, this.type ); - if ( image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof ImageBitmap ) { + } - if ( _canvas === undefined ) _canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); + // do blur pass for VSM - _canvas.width = _Math.floorPowerOfTwo( image.width ); - _canvas.height = _Math.floorPowerOfTwo( image.height ); + if ( ! shadow.isPointLightShadow && this.type === VSMShadowMap ) { - var context = _canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, _canvas.width, _canvas.height ); + VSMPass( shadow, camera ); - console.warn( 'THREE.WebGLRenderer: image is not power of two (' + image.width + 'x' + image.height + '). Resized to ' + _canvas.width + 'x' + _canvas.height ); + } - return _canvas; + shadow.needsUpdate = false; } - return image; + scope.needsUpdate = false; - } + _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); - function textureNeedsPowerOfTwo( texture ) { + }; - if ( capabilities.isWebGL2 ) return false; + function VSMPass( shadow, camera ) { - return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || - ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); + var geometry = _objects.update( fullScreenMesh ); - } + // vertical pass - function textureNeedsGenerateMipmaps( texture, isPowerOfTwo ) { + shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; + shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; + shadowMaterialVertical.uniforms.radius.value = shadow.radius; + _renderer.setRenderTarget( shadow.mapPass ); + _renderer.clear(); + _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null ); - return texture.generateMipmaps && isPowerOfTwo && - texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; + // horizonal pass + + shadowMaterialHorizonal.uniforms.shadow_pass.value = shadow.mapPass.texture; + shadowMaterialHorizonal.uniforms.resolution.value = shadow.mapSize; + shadowMaterialHorizonal.uniforms.radius.value = shadow.radius; + _renderer.setRenderTarget( shadow.map ); + _renderer.clear(); + _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizonal, fullScreenMesh, null ); } - function generateMipmap( target, texture, width, height ) { + function getDepthMaterialVariant( useMorphing, useSkinning, useInstancing ) { - _gl.generateMipmap( target ); + var index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2; - var textureProperties = properties.get( texture ); + var material = _depthMaterials[ index ]; - // Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11 - textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E; + if ( material === undefined ) { - } + material = new MeshDepthMaterial( { - function getInternalFormat( glFormat, glType ) { + depthPacking: RGBADepthPacking, - if ( ! capabilities.isWebGL2 ) return glFormat; + morphTargets: useMorphing, + skinning: useSkinning - if ( glFormat === 6403 ) { + } ); - if ( glType === 5126 ) return 33326; - if ( glType === 5131 ) return 33325; - if ( glType === 5121 ) return 33321; + _depthMaterials[ index ] = material; } - if ( glFormat === 6407 ) { - - if ( glType === 5126 ) return 34837; - if ( glType === 5131 ) return 34843; - if ( glType === 5121 ) return 32849; - - } + return material; - if ( glFormat === 6408 ) { + } - if ( glType === 5126 ) return 34836; - if ( glType === 5131 ) return 34842; - if ( glType === 5121 ) return 32856; + function getDistanceMaterialVariant( useMorphing, useSkinning, useInstancing ) { - } + var index = useMorphing << 0 | useSkinning << 1 | useInstancing << 2; - return glFormat; + var material = _distanceMaterials[ index ]; - } + if ( material === undefined ) { - // Fallback filters for non-power-of-2 textures + material = new MeshDistanceMaterial( { - function filterFallback( f ) { + morphTargets: useMorphing, + skinning: useSkinning - if ( f === NearestFilter || f === NearestMipMapNearestFilter || f === NearestMipMapLinearFilter ) { + } ); - return 9728; + _distanceMaterials[ index ] = material; } - return 9729; + return material; } - // - - function onTextureDispose( event ) { - - var texture = event.target; + function getDepthMaterial( object, geometry, material, light, shadowCameraNear, shadowCameraFar, type ) { - texture.removeEventListener( 'dispose', onTextureDispose ); + var result = null; - deallocateTexture( texture ); + var getMaterialVariant = getDepthMaterialVariant; + var customMaterial = object.customDepthMaterial; - if ( texture.isVideoTexture ) { + if ( light.isPointLight === true ) { - delete _videoTextures[ texture.id ]; + getMaterialVariant = getDistanceMaterialVariant; + customMaterial = object.customDistanceMaterial; } - info.memory.textures --; + if ( customMaterial === undefined ) { - } + var useMorphing = false; - function onRenderTargetDispose( event ) { + if ( material.morphTargets === true ) { - var renderTarget = event.target; + useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0; - renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); + } - deallocateRenderTarget( renderTarget ); + var useSkinning = false; - info.memory.textures --; + if ( object.isSkinnedMesh === true ) { - } + if ( material.skinning === true ) { - // + useSkinning = true; - function deallocateTexture( texture ) { + } else { - var textureProperties = properties.get( texture ); + console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object ); + + } - if ( texture.image && textureProperties.__image__webglTextureCube ) { + } - // cube texture + var useInstancing = object.isInstancedMesh === true; - _gl.deleteTexture( textureProperties.__image__webglTextureCube ); + result = getMaterialVariant( useMorphing, useSkinning, useInstancing ); } else { - // 2D texture + result = customMaterial; - if ( textureProperties.__webglInit === undefined ) return; + } - _gl.deleteTexture( textureProperties.__webglTexture ); + if ( _renderer.localClippingEnabled && + material.clipShadows === true && + material.clippingPlanes.length !== 0 ) { - } + // in this case we need a unique material instance reflecting the + // appropriate state - // remove all webgl properties - properties.remove( texture ); + var keyA = result.uuid, keyB = material.uuid; - } + var materialsForVariant = _materialCache[ keyA ]; - function deallocateRenderTarget( renderTarget ) { + if ( materialsForVariant === undefined ) { - var renderTargetProperties = properties.get( renderTarget ); - var textureProperties = properties.get( renderTarget.texture ); + materialsForVariant = {}; + _materialCache[ keyA ] = materialsForVariant; - if ( ! renderTarget ) return; + } - if ( textureProperties.__webglTexture !== undefined ) { + var cachedMaterial = materialsForVariant[ keyB ]; - _gl.deleteTexture( textureProperties.__webglTexture ); + if ( cachedMaterial === undefined ) { - } + cachedMaterial = result.clone(); + materialsForVariant[ keyB ] = cachedMaterial; - if ( renderTarget.depthTexture ) { + } - renderTarget.depthTexture.dispose(); + result = cachedMaterial; } - if ( renderTarget.isWebGLRenderTargetCube ) { - - for ( var i = 0; i < 6; i ++ ) { + result.visible = material.visible; + result.wireframe = material.wireframe; - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); + if ( type === VSMShadowMap ) { - } + result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side; } else { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); - if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); + result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ]; } - properties.remove( renderTarget.texture ); - properties.remove( renderTarget ); + result.clipShadows = material.clipShadows; + result.clippingPlanes = material.clippingPlanes; + result.clipIntersection = material.clipIntersection; - } + 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; + } - function setTexture2D( texture, slot ) { + return result; - var textureProperties = properties.get( texture ); + } - if ( texture.isVideoTexture ) updateVideoTexture( texture ); + function renderObject( object, camera, shadowCamera, light, type ) { - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + if ( object.visible === false ) { return; } - var image = texture.image; - - if ( image === undefined ) { - - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' ); - - } else if ( image.complete === false ) { + var visible = object.layers.test( camera.layers ); - console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); + if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { - } else { + if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { - uploadTexture( textureProperties, texture, slot ); - return; + object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); - } + var geometry = _objects.update( object ); + var material = object.material; - } + if ( Array.isArray( material ) ) { - state.activeTexture( 33984 + slot ); - state.bindTexture( 3553, textureProperties.__webglTexture ); + var groups = geometry.groups; - } + for ( var k = 0, kl = groups.length; k < kl; k ++ ) { - function setTexture3D( texture, slot ) { + var group = groups[ k ]; + var groupMaterial = material[ group.materialIndex ]; - var textureProperties = properties.get( texture ); + if ( groupMaterial && groupMaterial.visible ) { - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + var depthMaterial = getDepthMaterial( object, geometry, groupMaterial, light, shadowCamera.near, shadowCamera.far, type ); - uploadTexture( textureProperties, texture, slot ); - return; + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); - } + } - state.activeTexture( 33984 + slot ); - state.bindTexture( 32879, textureProperties.__webglTexture ); + } - } + } else if ( material.visible ) { + var depthMaterial$1 = getDepthMaterial( object, geometry, material, light, shadowCamera.near, shadowCamera.far, type ); - function setTextureCube( texture, slot ) { + _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial$1, object, null ); - var textureProperties = properties.get( texture ); + } - if ( texture.image.length === 6 ) { + } - if ( texture.version > 0 && textureProperties.__version !== texture.version ) { + } - if ( ! textureProperties.__image__webglTextureCube ) { + var children = object.children; - texture.addEventListener( 'dispose', onTextureDispose ); + for ( var i = 0, l = children.length; i < l; i ++ ) { - textureProperties.__image__webglTextureCube = _gl.createTexture(); + renderObject( children[ i ], camera, shadowCamera, light, type ); - info.memory.textures ++; + } - } + } - state.activeTexture( 33984 + slot ); - state.bindTexture( 34067, textureProperties.__image__webglTextureCube ); + } - _gl.pixelStorei( 37440, texture.flipY ); + function WebGLState( gl, extensions, capabilities ) { - var isCompressed = ( texture && texture.isCompressedTexture ); - var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); + var isWebGL2 = capabilities.isWebGL2; - var cubeImage = []; + function ColorBuffer() { - for ( var i = 0; i < 6; i ++ ) { + var locked = false; - if ( ! isCompressed && ! isDataTexture ) { + var color = new Vector4(); + var currentColorMask = null; + var currentColorClear = new Vector4( 0, 0, 0, 0 ); - cubeImage[ i ] = clampToMaxSize( texture.image[ i ], capabilities.maxCubemapSize ); + return { - } else { + setMask: function ( colorMask ) { - cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; + if ( currentColorMask !== colorMask && ! locked ) { - } + gl.colorMask( colorMask, colorMask, colorMask, colorMask ); + currentColorMask = colorMask; } - var image = cubeImage[ 0 ], - isPowerOfTwoImage = isPowerOfTwo( image ), - glFormat = utils.convert( texture.format ), - glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( glFormat, glType ); - - setTextureParameters( 34067, texture, isPowerOfTwoImage ); + }, - for ( var i = 0; i < 6; i ++ ) { + setLocked: function ( lock ) { - if ( ! isCompressed ) { + locked = lock; - if ( isDataTexture ) { + }, - state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); + setClear: function ( r, g, b, a, premultipliedAlpha ) { - } else { + if ( premultipliedAlpha === true ) { - state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); + r *= a; g *= a; b *= a; - } + } - } else { + color.set( r, g, b, a ); - var mipmap, mipmaps = cubeImage[ i ].mipmaps; + if ( currentColorClear.equals( color ) === false ) { - for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { + gl.clearColor( r, g, b, a ); + currentColorClear.copy( color ); - mipmap = mipmaps[ j ]; + } - if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { + }, - if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { + reset: function () { - state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + locked = false; - } else { + currentColorMask = null; + currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state - 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 ); + function DepthBuffer() { - } + var locked = false; - } + var currentDepthMask = null; + var currentDepthFunc = null; + var currentDepthClear = null; - } + return { - } + setTest: function ( depthTest ) { - if ( ! isCompressed ) { + if ( depthTest ) { - textureProperties.__maxMipLevel = 0; + enable( 2929 ); } else { - textureProperties.__maxMipLevel = mipmaps.length - 1; - - } - - if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) { - - // We assume images for cube map have the same size. - generateMipmap( 34067, texture, image.width, image.height ); + disable( 2929 ); } - textureProperties.__version = texture.version; + }, - if ( texture.onUpdate ) texture.onUpdate( texture ); + setMask: function ( depthMask ) { - } else { + if ( currentDepthMask !== depthMask && ! locked ) { - state.activeTexture( 33984 + slot ); - state.bindTexture( 34067, textureProperties.__image__webglTextureCube ); + gl.depthMask( depthMask ); + currentDepthMask = depthMask; - } + } - } + }, - } + setFunc: function ( depthFunc ) { - function setTextureCubeDynamic( texture, slot ) { + if ( currentDepthFunc !== depthFunc ) { - state.activeTexture( 33984 + slot ); - state.bindTexture( 34067, properties.get( texture ).__webglTexture ); + if ( depthFunc ) { - } + switch ( depthFunc ) { - function setTextureParameters( textureType, texture, isPowerOfTwoImage ) { + case NeverDepth: - var extension; + gl.depthFunc( 512 ); + break; - if ( isPowerOfTwoImage ) { + case AlwaysDepth: - _gl.texParameteri( textureType, 10242, utils.convert( texture.wrapS ) ); - _gl.texParameteri( textureType, 10243, utils.convert( texture.wrapT ) ); + gl.depthFunc( 519 ); + break; - _gl.texParameteri( textureType, 10240, utils.convert( texture.magFilter ) ); - _gl.texParameteri( textureType, 10241, utils.convert( texture.minFilter ) ); + case LessDepth: - } else { + gl.depthFunc( 513 ); + break; - _gl.texParameteri( textureType, 10242, 33071 ); - _gl.texParameteri( textureType, 10243, 33071 ); + case LessEqualDepth: - if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { + gl.depthFunc( 515 ); + break; - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); + case EqualDepth: - } + gl.depthFunc( 514 ); + break; - _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); + case GreaterEqualDepth: - if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { + gl.depthFunc( 518 ); + break; - console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); + case GreaterDepth: - } + gl.depthFunc( 516 ); + break; - } + case NotEqualDepth: - extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + gl.depthFunc( 517 ); + break; - if ( extension ) { + default: - if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) return; - if ( texture.type === HalfFloatType && ( capabilities.isWebGL2 || extensions.get( 'OES_texture_half_float_linear' ) ) === null ) return; + gl.depthFunc( 515 ); - 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; + } else { - } + gl.depthFunc( 515 ); - } + } - } + currentDepthFunc = depthFunc; - function uploadTexture( textureProperties, texture, slot ) { + } - var textureType; + }, - if ( texture.isDataTexture3D ) { + setLocked: function ( lock ) { - textureType = 32879; + locked = lock; - } else { + }, - textureType = 3553; + setClear: function ( depth ) { - } + if ( currentDepthClear !== depth ) { + gl.clearDepth( depth ); + currentDepthClear = depth; - if ( textureProperties.__webglInit === undefined ) { + } - textureProperties.__webglInit = true; + }, - texture.addEventListener( 'dispose', onTextureDispose ); + reset: function () { - textureProperties.__webglTexture = _gl.createTexture(); + locked = false; - info.memory.textures ++; + currentDepthMask = null; + currentDepthFunc = null; + currentDepthClear = null; - } - state.activeTexture( 33984 + slot ); + } + }; - state.bindTexture( textureType, textureProperties.__webglTexture ); + } + function StencilBuffer() { + var locked = false; - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); + var currentStencilMask = null; + var currentStencilFunc = null; + var currentStencilRef = null; + var currentStencilFuncMask = null; + var currentStencilFail = null; + var currentStencilZFail = null; + var currentStencilZPass = null; + var currentStencilClear = null; - var image = clampToMaxSize( texture.image, capabilities.maxTextureSize ); + return { - if ( textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( image ) === false ) { + setTest: function ( stencilTest ) { - image = makePowerOfTwo( image ); + if ( ! locked ) { - } + if ( stencilTest ) { - var isPowerOfTwoImage = isPowerOfTwo( image ), - glFormat = utils.convert( texture.format ), - glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( glFormat, glType ); + enable( 2960 ); - setTextureParameters( textureType, texture, isPowerOfTwoImage ); + } else { - var mipmap, mipmaps = texture.mipmaps; + disable( 2960 ); - if ( texture.isDepthTexture ) { + } - // populate depth texture with dummy data + } - glInternalFormat = 6402; + }, - if ( texture.type === FloatType ) { + setMask: function ( stencilMask ) { - if ( ! capabilities.isWebGL2 ) throw new Error( 'Float Depth Texture only supported in WebGL2.0' ); - glInternalFormat = 36012; + if ( currentStencilMask !== stencilMask && ! locked ) { - } else if ( capabilities.isWebGL2 ) { + gl.stencilMask( stencilMask ); + currentStencilMask = stencilMask; - // WebGL 2.0 requires signed internalformat for glTexImage2D - glInternalFormat = 33189; + } - } + }, - if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { + setFunc: function ( stencilFunc, stencilRef, stencilMask ) { - // 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 ) { + if ( currentStencilFunc !== stencilFunc || + currentStencilRef !== stencilRef || + currentStencilFuncMask !== stencilMask ) { - console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); + gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); - texture.type = UnsignedShortType; - glType = utils.convert( texture.type ); + currentStencilFunc = stencilFunc; + currentStencilRef = stencilRef; + currentStencilFuncMask = stencilMask; } - } - - // Depth stencil textures need the DEPTH_STENCIL internal format - // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - if ( texture.format === DepthStencilFormat ) { + }, - glInternalFormat = 34041; + setOp: function ( stencilFail, stencilZFail, stencilZPass ) { - // 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 ) { + if ( currentStencilFail !== stencilFail || + currentStencilZFail !== stencilZFail || + currentStencilZPass !== stencilZPass ) { - console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); + gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); - texture.type = UnsignedInt248Type; - glType = utils.convert( texture.type ); + currentStencilFail = stencilFail; + currentStencilZFail = stencilZFail; + currentStencilZPass = stencilZPass; } - } + }, - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); + setLocked: function ( lock ) { - } else if ( texture.isDataTexture ) { + locked = lock; - // 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 && isPowerOfTwoImage ) { + setClear: function ( stencil ) { - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + if ( currentStencilClear !== stencil ) { - mipmap = mipmaps[ i ]; - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + gl.clearStencil( stencil ); + currentStencilClear = stencil; } - 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; + }, - } + reset: function () { - } else if ( texture.isCompressedTexture ) { + locked = false; - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + currentStencilMask = null; + currentStencilFunc = null; + currentStencilRef = null; + currentStencilFuncMask = null; + currentStencilFail = null; + currentStencilZFail = null; + currentStencilZPass = null; + currentStencilClear = null; - mipmap = mipmaps[ i ]; + } - if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { + }; - if ( state.getCompressedTextureFormats().indexOf( glFormat ) > - 1 ) { + } - state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + // - } else { + var colorBuffer = new ColorBuffer(); + var depthBuffer = new DepthBuffer(); + var stencilBuffer = new StencilBuffer(); - console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); + var enabledCapabilities = {}; - } + var currentProgram = null; - } else { + var currentBlendingEnabled = null; + var currentBlending = null; + var currentBlendEquation = null; + var currentBlendSrc = null; + var currentBlendDst = null; + var currentBlendEquationAlpha = null; + var currentBlendSrcAlpha = null; + var currentBlendDstAlpha = null; + var currentPremultipledAlpha = false; - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + var currentFlipSided = null; + var currentCullFace = null; - } + var currentLineWidth = null; - } + var currentPolygonOffsetFactor = null; + var currentPolygonOffsetUnits = null; - textureProperties.__maxMipLevel = mipmaps.length - 1; + var maxTextures = gl.getParameter( 35661 ); - } else if ( texture.isDataTexture3D ) { + var lineWidthAvailable = false; + var version = 0; + var glVersion = gl.getParameter( 7938 ); - state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); - textureProperties.__maxMipLevel = 0; + if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { - } else { + version = parseFloat( /^WebGL\ ([0-9])/.exec( glVersion )[ 1 ] ); + lineWidthAvailable = ( version >= 1.0 ); - // regular Texture (image, video, canvas) + } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) { - // 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 + version = parseFloat( /^OpenGL\ ES\ ([0-9])/.exec( glVersion )[ 1 ] ); + lineWidthAvailable = ( version >= 2.0 ); - if ( mipmaps.length > 0 && isPowerOfTwoImage ) { + } - for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { + var currentTextureSlot = null; + var currentBoundTextures = {}; - mipmap = mipmaps[ i ]; - state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap ); + var currentScissor = new Vector4(); + var currentViewport = new Vector4(); - } + function createTexture( type, target, count ) { - texture.generateMipmaps = false; - textureProperties.__maxMipLevel = mipmaps.length - 1; + var data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. + var texture = gl.createTexture(); - } else { + gl.bindTexture( type, texture ); + gl.texParameteri( type, 10241, 9728 ); + gl.texParameteri( type, 10240, 9728 ); - state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); - textureProperties.__maxMipLevel = 0; + for ( var i = 0; i < count; i ++ ) { - } + gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); } - if ( textureNeedsGenerateMipmaps( texture, isPowerOfTwoImage ) ) { - - generateMipmap( 3553, texture, image.width, image.height ); + return texture; - } + } - textureProperties.__version = texture.version; + var emptyTextures = {}; + emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); + emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); - if ( texture.onUpdate ) texture.onUpdate( texture ); + // init - } + colorBuffer.setClear( 0, 0, 0, 1 ); + depthBuffer.setClear( 1 ); + stencilBuffer.setClear( 0 ); - // Render targets + enable( 2929 ); + depthBuffer.setFunc( LessEqualDepth ); - // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) { + setFlipSided( false ); + setCullFace( CullFaceBack ); + enable( 2884 ); - var glFormat = utils.convert( renderTarget.texture.format ); - var glType = utils.convert( renderTarget.texture.type ); - var glInternalFormat = getInternalFormat( glFormat, glType ); - state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); - _gl.bindFramebuffer( 36160, framebuffer ); - _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 ); - _gl.bindFramebuffer( 36160, null ); + setBlending( NoBlending ); - } + // - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer - function setupRenderBufferStorage( renderbuffer, renderTarget ) { + function enable( id ) { - _gl.bindRenderbuffer( 36161, renderbuffer ); + if ( enabledCapabilities[ id ] !== true ) { - if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { + gl.enable( id ); + enabledCapabilities[ id ] = true; - _gl.renderbufferStorage( 36161, 33189, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); + } - } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { + } - _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); + function disable( id ) { - } else { + if ( enabledCapabilities[ id ] !== false ) { - // FIXME: We don't support !depth !stencil - _gl.renderbufferStorage( 36161, 32854, renderTarget.width, renderTarget.height ); + gl.disable( id ); + enabledCapabilities[ id ] = false; } - _gl.bindRenderbuffer( 36161, null ); - } - // Setup resources for a Depth Texture for a FBO (needs an extension) - function setupDepthTexture( framebuffer, renderTarget ) { + function useProgram( program ) { - var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube ); - if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); + if ( currentProgram !== program ) { - _gl.bindFramebuffer( 36160, framebuffer ); + gl.useProgram( program ); - if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { + currentProgram = program; - throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); + return true; } - // 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; - - } + return false; - setTexture2D( renderTarget.depthTexture, 0 ); + } - var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; + var equationToGL = {}; + equationToGL[ AddEquation ] = 32774; + equationToGL[ SubtractEquation ] = 32778; + equationToGL[ ReverseSubtractEquation ] = 32779; - if ( renderTarget.depthTexture.format === DepthFormat ) { + if ( isWebGL2 ) { - _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); + equationToGL[ MinEquation ] = 32775; + equationToGL[ MaxEquation ] = 32776; - } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { + } else { - _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); + var extension = extensions.get( 'EXT_blend_minmax' ); - } else { + if ( extension !== null ) { - throw new Error( 'Unknown depthTexture format' ); + equationToGL[ MinEquation ] = extension.MIN_EXT; + equationToGL[ MaxEquation ] = extension.MAX_EXT; } } - // Setup GL resources for a non-texture depth buffer - function setupDepthRenderbuffer( renderTarget ) { - - var renderTargetProperties = properties.get( renderTarget ); + var factorToGL = {}; + factorToGL[ ZeroFactor ] = 0; + factorToGL[ OneFactor ] = 1; + factorToGL[ SrcColorFactor ] = 768; + factorToGL[ SrcAlphaFactor ] = 770; + factorToGL[ SrcAlphaSaturateFactor ] = 776; + factorToGL[ DstColorFactor ] = 774; + factorToGL[ DstAlphaFactor ] = 772; + factorToGL[ OneMinusSrcColorFactor ] = 769; + factorToGL[ OneMinusSrcAlphaFactor ] = 771; + factorToGL[ OneMinusDstColorFactor ] = 775; + factorToGL[ OneMinusDstAlphaFactor ] = 773; - var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); + function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { - if ( renderTarget.depthTexture ) { + if ( blending === NoBlending ) { - if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); + if ( currentBlendingEnabled ) { - setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); + disable( 3042 ); + currentBlendingEnabled = false; - } else { + } - if ( isCube ) { + return; - renderTargetProperties.__webglDepthbuffer = []; + } - for ( var i = 0; i < 6; i ++ ) { + if ( ! currentBlendingEnabled ) { - _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); - renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget ); + enable( 3042 ); + currentBlendingEnabled = true; - } + } - } else { + if ( blending !== CustomBlending ) { - _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); - renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); - setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget ); + if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { - } + if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { - } + gl.blendEquation( 32774 ); - _gl.bindFramebuffer( 36160, null ); + currentBlendEquation = AddEquation; + currentBlendEquationAlpha = AddEquation; - } + } - // Set up GL resources for the render target - function setupRenderTarget( renderTarget ) { + if ( premultipliedAlpha ) { - var renderTargetProperties = properties.get( renderTarget ); - var textureProperties = properties.get( renderTarget.texture ); + switch ( blending ) { - renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); + case NormalBlending: + gl.blendFuncSeparate( 1, 771, 1, 771 ); + break; - textureProperties.__webglTexture = _gl.createTexture(); - - info.memory.textures ++; + case AdditiveBlending: + gl.blendFunc( 1, 1 ); + break; - var isCube = ( renderTarget.isWebGLRenderTargetCube === true ); - var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); + case SubtractiveBlending: + gl.blendFuncSeparate( 0, 0, 769, 771 ); + break; - // Setup framebuffer + case MultiplyBlending: + gl.blendFuncSeparate( 0, 768, 0, 770 ); + break; - if ( isCube ) { + default: + console.error( 'THREE.WebGLState: Invalid blending: ', blending ); + break; - renderTargetProperties.__webglFramebuffer = []; + } - for ( var i = 0; i < 6; i ++ ) { + } else { - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + switch ( blending ) { - } + case NormalBlending: + gl.blendFuncSeparate( 770, 771, 1, 771 ); + break; - } else { + case AdditiveBlending: + gl.blendFunc( 770, 1 ); + break; - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + case SubtractiveBlending: + gl.blendFunc( 0, 769 ); + break; - } + case MultiplyBlending: + gl.blendFunc( 0, 768 ); + break; - // Setup color buffer + default: + console.error( 'THREE.WebGLState: Invalid blending: ', blending ); + break; - if ( isCube ) { + } - state.bindTexture( 34067, textureProperties.__webglTexture ); - setTextureParameters( 34067, renderTarget.texture, isTargetPowerOfTwo ); + } - for ( var i = 0; i < 6; i ++ ) { + currentBlendSrc = null; + currentBlendDst = null; + currentBlendSrcAlpha = null; + currentBlendDstAlpha = null; - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, 36064, 34069 + i ); + currentBlending = blending; + currentPremultipledAlpha = premultipliedAlpha; } - if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) { + return; - generateMipmap( 34067, renderTarget.texture, renderTarget.width, renderTarget.height ); + } - } + // custom blending - state.bindTexture( 34067, null ); + blendEquationAlpha = blendEquationAlpha || blendEquation; + blendSrcAlpha = blendSrcAlpha || blendSrc; + blendDstAlpha = blendDstAlpha || blendDst; - } else { + if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { - state.bindTexture( 3553, textureProperties.__webglTexture ); - setTextureParameters( 3553, renderTarget.texture, isTargetPowerOfTwo ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, 36064, 3553 ); + gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); - if ( textureNeedsGenerateMipmaps( renderTarget.texture, isTargetPowerOfTwo ) ) { + currentBlendEquation = blendEquation; + currentBlendEquationAlpha = blendEquationAlpha; - generateMipmap( 3553, renderTarget.texture, renderTarget.width, renderTarget.height ); + } - } + if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { - state.bindTexture( 3553, null ); + gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); + + currentBlendSrc = blendSrc; + currentBlendDst = blendDst; + currentBlendSrcAlpha = blendSrcAlpha; + currentBlendDstAlpha = blendDstAlpha; } - // Setup depth and stencil buffers + currentBlending = blending; + currentPremultipledAlpha = null; - if ( renderTarget.depthBuffer ) { + } - setupDepthRenderbuffer( renderTarget ); + function setMaterial( material, frontFaceCW ) { - } + material.side === DoubleSide + ? disable( 2884 ) + : enable( 2884 ); - } + var flipSided = ( material.side === BackSide ); + if ( frontFaceCW ) { flipSided = ! flipSided; } - function updateRenderTargetMipmap( renderTarget ) { + setFlipSided( flipSided ); - var texture = renderTarget.texture; - var isTargetPowerOfTwo = isPowerOfTwo( renderTarget ); + ( 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 ); - if ( textureNeedsGenerateMipmaps( texture, isTargetPowerOfTwo ) ) { + depthBuffer.setFunc( material.depthFunc ); + depthBuffer.setTest( material.depthTest ); + depthBuffer.setMask( material.depthWrite ); + colorBuffer.setMask( material.colorWrite ); - var target = renderTarget.isWebGLRenderTargetCube ? 34067 : 3553; - var webglTexture = properties.get( texture ).__webglTexture; + var stencilWrite = material.stencilWrite; + stencilBuffer.setTest( stencilWrite ); + if ( stencilWrite ) { - state.bindTexture( target, webglTexture ); - generateMipmap( target, texture, renderTarget.width, renderTarget.height ); - state.bindTexture( target, null ); + 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 ); + } - function updateVideoTexture( texture ) { + // - var id = texture.id; - var frame = info.render.frame; + function setFlipSided( flipSided ) { - // Check the last frame we updated the VideoTexture + if ( currentFlipSided !== flipSided ) { - if ( _videoTextures[ id ] !== frame ) { + if ( flipSided ) { - _videoTextures[ id ] = frame; - texture.update(); + gl.frontFace( 2304 ); + + } else { + + gl.frontFace( 2305 ); + + } + + currentFlipSided = flipSided; } } - this.setTexture2D = setTexture2D; - this.setTexture3D = setTexture3D; - this.setTextureCube = setTextureCube; - this.setTextureCubeDynamic = setTextureCubeDynamic; - this.setupRenderTarget = setupRenderTarget; - this.updateRenderTargetMipmap = updateRenderTargetMipmap; - - } + function setCullFace( cullFace ) { - /** - * @author thespite / http://www.twitter.com/thespite - */ + if ( cullFace !== CullFaceNone ) { - function WebGLUtils( gl, extensions, capabilities ) { + enable( 2884 ); - function convert( p ) { + if ( cullFace !== currentCullFace ) { - var extension; + if ( cullFace === CullFaceBack ) { - if ( p === RepeatWrapping ) return 10497; - if ( p === ClampToEdgeWrapping ) return 33071; - if ( p === MirroredRepeatWrapping ) return 33648; + gl.cullFace( 1029 ); - if ( p === NearestFilter ) return 9728; - if ( p === NearestMipMapNearestFilter ) return 9984; - if ( p === NearestMipMapLinearFilter ) return 9986; + } else if ( cullFace === CullFaceFront ) { - if ( p === LinearFilter ) return 9729; - if ( p === LinearMipMapNearestFilter ) return 9985; - if ( p === LinearMipMapLinearFilter ) return 9987; + gl.cullFace( 1028 ); - if ( p === UnsignedByteType ) return 5121; - if ( p === UnsignedShort4444Type ) return 32819; - if ( p === UnsignedShort5551Type ) return 32820; - if ( p === UnsignedShort565Type ) return 33635; + } else { - 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; + gl.cullFace( 1032 ); - if ( p === HalfFloatType ) { + } - if ( capabilities.isWebGL2 ) return 5131; + } - extension = extensions.get( 'OES_texture_half_float' ); + } else { - if ( extension !== null ) return extension.HALF_FLOAT_OES; + disable( 2884 ); } - 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; + currentCullFace = cullFace; - if ( p === AddEquation ) return 32774; - if ( p === SubtractEquation ) return 32778; - if ( p === ReverseSubtractEquation ) return 32779; + } - if ( p === ZeroFactor ) return 0; - if ( p === OneFactor ) return 1; - if ( p === SrcColorFactor ) return 768; - if ( p === OneMinusSrcColorFactor ) return 769; - if ( p === SrcAlphaFactor ) return 770; - if ( p === OneMinusSrcAlphaFactor ) return 771; - if ( p === DstAlphaFactor ) return 772; - if ( p === OneMinusDstAlphaFactor ) return 773; + function setLineWidth( width ) { - if ( p === DstColorFactor ) return 774; - if ( p === OneMinusDstColorFactor ) return 775; - if ( p === SrcAlphaSaturateFactor ) return 776; + if ( width !== currentLineWidth ) { - if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || - p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { + if ( lineWidthAvailable ) { gl.lineWidth( width ); } - extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); + currentLineWidth = width; - 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; + } - } + function setPolygonOffset( polygonOffset, factor, units ) { - } + if ( polygonOffset ) { - if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || - p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { + enable( 32823 ); - extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { - if ( extension !== null ) { + gl.polygonOffset( factor, units ); - 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; + currentPolygonOffsetFactor = factor; + currentPolygonOffsetUnits = units; } + } else { + + disable( 32823 ); + } - if ( p === RGB_ETC1_Format ) { + } - extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); + function setScissorTest( scissorTest ) { + + if ( scissorTest ) { + + enable( 3089 ); + + } else { - if ( extension !== null ) return extension.COMPRESSED_RGB_ETC1_WEBGL; + disable( 3089 ); } - 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 ) { + } - extension = extensions.get( 'WEBGL_compressed_texture_astc' ); + // texture - if ( extension !== null ) { + function activeTexture( webglSlot ) { - return p; + if ( webglSlot === undefined ) { webglSlot = 33984 + maxTextures - 1; } - } + if ( currentTextureSlot !== webglSlot ) { + + gl.activeTexture( webglSlot ); + currentTextureSlot = webglSlot; } - if ( p === MinEquation || p === MaxEquation ) { + } - if ( capabilities.isWebGL2 ) { + function bindTexture( webglType, webglTexture ) { - if ( p === MinEquation ) return 32775; - if ( p === MaxEquation ) return 32776; + if ( currentTextureSlot === null ) { - } + activeTexture(); - extension = extensions.get( 'EXT_blend_minmax' ); + } - if ( extension !== null ) { + var boundTexture = currentBoundTextures[ currentTextureSlot ]; - if ( p === MinEquation ) return extension.MIN_EXT; - if ( p === MaxEquation ) return extension.MAX_EXT; + if ( boundTexture === undefined ) { - } + boundTexture = { type: undefined, texture: undefined }; + currentBoundTextures[ currentTextureSlot ] = boundTexture; } - if ( p === UnsignedInt248Type ) { - - if ( capabilities.isWebGL2 ) return 34042; + if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { - extension = extensions.get( 'WEBGL_depth_texture' ); + gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); - if ( extension !== null ) return extension.UNSIGNED_INT_24_8_WEBGL; + boundTexture.type = webglType; + boundTexture.texture = webglTexture; } - return 0; - } - return { convert: convert }; + function unbindTexture() { - } + var boundTexture = currentBoundTextures[ currentTextureSlot ]; - /** - * @author mrdoob / http://mrdoob.com/ - */ + if ( boundTexture !== undefined && boundTexture.type !== undefined ) { - function Group() { + gl.bindTexture( boundTexture.type, null ); - Object3D.call( this ); + boundTexture.type = undefined; + boundTexture.texture = undefined; - this.type = 'Group'; + } - } + } - Group.prototype = Object.assign( Object.create( Object3D.prototype ), { + function compressedTexImage2D() { - constructor: Group, + try { - isGroup: true + gl.compressedTexImage2D.apply( gl, arguments ); - } ); + } catch ( error ) { - /** - * @author mrdoob / http://mrdoob.com/ - * @author mikael emtinger / http://gomo.se/ - * @author WestLangley / http://github.com/WestLangley - */ + console.error( 'THREE.WebGLState:', error ); - function Camera() { + } - Object3D.call( this ); + } - this.type = 'Camera'; + function texImage2D() { - this.matrixWorldInverse = new Matrix4(); + try { - this.projectionMatrix = new Matrix4(); - this.projectionMatrixInverse = new Matrix4(); + gl.texImage2D.apply( gl, arguments ); - } + } catch ( error ) { - Camera.prototype = Object.assign( Object.create( Object3D.prototype ), { + console.error( 'THREE.WebGLState:', error ); - constructor: Camera, + } - isCamera: true, + } - copy: function ( source, recursive ) { + function texImage3D() { - Object3D.prototype.copy.call( this, source, recursive ); + try { - this.matrixWorldInverse.copy( source.matrixWorldInverse ); + gl.texImage3D.apply( gl, arguments ); - this.projectionMatrix.copy( source.projectionMatrix ); - this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); + } catch ( error ) { - return this; + console.error( 'THREE.WebGLState:', error ); - }, + } - getWorldDirection: function ( target ) { + } - if ( target === undefined ) { + // - console.warn( 'THREE.Camera: .getWorldDirection() target is now required' ); - target = new Vector3(); + function scissor( scissor ) { - } + if ( currentScissor.equals( scissor ) === false ) { - this.updateMatrixWorld( true ); + gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); + currentScissor.copy( scissor ); - var e = this.matrixWorld.elements; + } - return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); + } - }, + function viewport( viewport ) { - updateMatrixWorld: function ( force ) { + if ( currentViewport.equals( viewport ) === false ) { - Object3D.prototype.updateMatrixWorld.call( this, force ); + gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); + currentViewport.copy( viewport ); - this.matrixWorldInverse.getInverse( this.matrixWorld ); + } - }, + } - clone: function () { + // - return new this.constructor().copy( this ); + function reset() { - } + enabledCapabilities = {}; - } ); + currentTextureSlot = null; + currentBoundTextures = {}; - /** - * @author mrdoob / http://mrdoob.com/ - * @author greggman / http://games.greggman.com/ - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author tschw - */ + currentProgram = null; - function PerspectiveCamera( fov, aspect, near, far ) { + currentBlending = null; - Camera.call( this ); + currentFlipSided = null; + currentCullFace = null; - this.type = 'PerspectiveCamera'; + colorBuffer.reset(); + depthBuffer.reset(); + stencilBuffer.reset(); - this.fov = fov !== undefined ? fov : 50; - this.zoom = 1; + } - this.near = near !== undefined ? near : 0.1; - this.far = far !== undefined ? far : 2000; - this.focus = 10; + return { - this.aspect = aspect !== undefined ? aspect : 1; - this.view = null; + buffers: { + color: colorBuffer, + depth: depthBuffer, + stencil: stencilBuffer + }, - this.filmGauge = 35; // width of the film (default in millimeters) - this.filmOffset = 0; // horizontal film offset (same unit as gauge) + enable: enable, + disable: disable, - this.updateProjectionMatrix(); + useProgram: useProgram, - } + setBlending: setBlending, + setMaterial: setMaterial, - PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ), { + setFlipSided: setFlipSided, + setCullFace: setCullFace, - constructor: PerspectiveCamera, + setLineWidth: setLineWidth, + setPolygonOffset: setPolygonOffset, - isPerspectiveCamera: true, + setScissorTest: setScissorTest, - copy: function ( source, recursive ) { + activeTexture: activeTexture, + bindTexture: bindTexture, + unbindTexture: unbindTexture, + compressedTexImage2D: compressedTexImage2D, + texImage2D: texImage2D, + texImage3D: texImage3D, - Camera.prototype.copy.call( this, source, recursive ); + scissor: scissor, + viewport: viewport, - this.fov = source.fov; - this.zoom = source.zoom; + reset: reset - 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; + function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { - return this; + var isWebGL2 = capabilities.isWebGL2; + var maxTextures = capabilities.maxTextures; + var maxCubemapSize = capabilities.maxCubemapSize; + var maxTextureSize = capabilities.maxTextureSize; + var maxSamples = capabilities.maxSamples; - }, + var _videoTextures = new WeakMap(); + var _canvas; - /** - * 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: function ( focalLength ) { + // 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). - // see http://www.bobatkins.com/photography/technical/field_of_view.html - var vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; + var useOffscreenCanvas = false; - this.fov = _Math.RAD2DEG * 2 * Math.atan( vExtentSlope ); - this.updateProjectionMatrix(); + try { - }, + useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' + && ( new OffscreenCanvas( 1, 1 ).getContext( "2d" ) ) !== null; - /** - * Calculates the focal length from the current .fov and .filmGauge. - */ - getFocalLength: function () { + } catch ( err ) { - var vExtentSlope = Math.tan( _Math.DEG2RAD * 0.5 * this.fov ); + // Ignore any errors - return 0.5 * this.getFilmHeight() / vExtentSlope; + } - }, + function createCanvas( width, height ) { - getEffectiveFOV: function () { + // Use OffscreenCanvas when available. Specially needed in web workers - return _Math.RAD2DEG * 2 * Math.atan( - Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom ); + return useOffscreenCanvas ? + new OffscreenCanvas( width, height ) : + document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ); - }, + } - getFilmWidth: function () { + function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) { - // film not completely covered in portrait format (aspect < 1) - return this.filmGauge * Math.min( this.aspect, 1 ); + var scale = 1; - }, + // handle case if texture exceeds max size - getFilmHeight: function () { + if ( image.width > maxSize || image.height > maxSize ) { - // film not completely covered in landscape format (aspect > 1) - return this.filmGauge / Math.max( this.aspect, 1 ); + scale = maxSize / Math.max( image.width, image.height ); - }, + } - /** - * Sets an offset in a larger frustum. This is useful for multi-window or - * multi-monitor/multi-machine setups. - * - * For example, if you have 3x2 monitors and each monitor is 1920x1080 and - * the monitors are in grid like this - * - * +---+---+---+ - * | A | B | C | - * +---+---+---+ - * | D | E | F | - * +---+---+---+ - * - * then for each monitor you would call it like this - * - * var w = 1920; - * var h = 1080; - * var fullWidth = w * 3; - * var fullHeight = h * 2; - * - * --A-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); - * --B-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); - * --C-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); - * --D-- - * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); - * --E-- - * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); - * --F-- - * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); - * - * Note there is no reason monitors have to be the same size or in a grid. - */ - setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) { + // only perform resize if necessary - this.aspect = fullWidth / fullHeight; + if ( scale < 1 || needsPowerOfTwo === true ) { - if ( this.view === null ) { + // only perform resize for certain image types - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - } + var floor = needsPowerOfTwo ? MathUtils.floorPowerOfTwo : Math.floor; - 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; + var width = floor( scale * image.width ); + var height = floor( scale * image.height ); - this.updateProjectionMatrix(); + if ( _canvas === undefined ) { _canvas = createCanvas( width, height ); } - }, + // cube textures can't reuse the same canvas - clearViewOffset: function () { + var canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas; - if ( this.view !== null ) { + canvas.width = width; + canvas.height = height; - this.view.enabled = false; + var 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 + ').' ); - this.updateProjectionMatrix(); + return canvas; - }, + } else { - updateProjectionMatrix: function () { + if ( 'data' in image ) { - var near = this.near, - top = near * Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom, - height = 2 * top, - width = this.aspect * height, - left = - 0.5 * width, - view = this.view; + console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); - if ( this.view !== null && this.view.enabled ) { + } - var fullWidth = view.fullWidth, - fullHeight = view.fullHeight; + return image; - left += view.offsetX * width / fullWidth; - top -= view.offsetY * height / fullHeight; - width *= view.width / fullWidth; - height *= view.height / fullHeight; + } } - var skew = this.filmOffset; - if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); + return image; - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); + } - this.projectionMatrixInverse.getInverse( this.projectionMatrix ); + function isPowerOfTwo( image ) { - }, + return MathUtils.isPowerOfTwo( image.width ) && MathUtils.isPowerOfTwo( image.height ); - toJSON: function ( meta ) { + } - var data = Object3D.prototype.toJSON.call( this, meta ); + function textureNeedsPowerOfTwo( texture ) { - data.object.fov = this.fov; - data.object.zoom = this.zoom; + if ( isWebGL2 ) { return false; } - data.object.near = this.near; - data.object.far = this.far; - data.object.focus = this.focus; + return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || + ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); - data.object.aspect = this.aspect; + } - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + function textureNeedsGenerateMipmaps( texture, supportsMips ) { - data.object.filmGauge = this.filmGauge; - data.object.filmOffset = this.filmOffset; - - return data; + return texture.generateMipmaps && supportsMips && + texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; } - } ); - - /** - * @author mrdoob / http://mrdoob.com/ - */ + function generateMipmap( target, texture, width, height ) { - function ArrayCamera( array ) { + _gl.generateMipmap( target ); - PerspectiveCamera.call( this ); + var textureProperties = properties.get( texture ); - this.cameras = array || []; + // Note: Math.log( x ) * Math.LOG2E used instead of Math.log2( x ) which is not supported by IE11 + textureProperties.__maxMipLevel = Math.log( Math.max( width, height ) ) * Math.LOG2E; - } + } - ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), { + function getInternalFormat( internalFormatName, glFormat, glType ) { - constructor: ArrayCamera, + if ( isWebGL2 === false ) { return glFormat; } - isArrayCamera: true + if ( internalFormatName !== null ) { - } ); + if ( _gl[ internalFormatName ] !== undefined ) { return _gl[ internalFormatName ]; } - /** - * @author jsantell / https://www.jsantell.com/ - * @author mrdoob / http://mrdoob.com/ - */ + console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); - var cameraLPos = new Vector3(); - var 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 ) { + var internalFormat = glFormat; - cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); - cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); + if ( glFormat === 6403 ) { - var ipd = cameraLPos.distanceTo( cameraRPos ); + if ( glType === 5126 ) { internalFormat = 33326; } + if ( glType === 5131 ) { internalFormat = 33325; } + if ( glType === 5121 ) { internalFormat = 33321; } - var projL = cameraL.projectionMatrix.elements; - var 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. - var near = projL[ 14 ] / ( projL[ 10 ] - 1 ); - var far = projL[ 14 ] / ( projL[ 10 ] + 1 ); - var topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; - var bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; + if ( glFormat === 6407 ) { - var leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; - var rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; - var left = near * leftFov; - var right = near * rightFov; + if ( glType === 5126 ) { internalFormat = 34837; } + if ( glType === 5131 ) { internalFormat = 34843; } + if ( glType === 5121 ) { internalFormat = 32849; } - // Calculate the new camera's position offset from the - // left camera. xOffset should be roughly half `ipd`. - var zOffset = ipd / ( - leftFov + rightFov ); - var 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.getInverse( camera.matrixWorld ); + if ( glFormat === 6408 ) { - // 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. - var near2 = near + zOffset; - var far2 = far + zOffset; - var left2 = left - xOffset; - var right2 = right + ( ipd - xOffset ); - var top2 = topFov * far / far2 * near2; - var bottom2 = bottomFov * far / far2 * near2; + if ( glType === 5126 ) { internalFormat = 34836; } + if ( glType === 5131 ) { internalFormat = 34842; } + if ( glType === 5121 ) { internalFormat = 32856; } - camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); + } - } + if ( internalFormat === 33325 || internalFormat === 33326 || + internalFormat === 34842 || internalFormat === 34836 ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + extensions.get( 'EXT_color_buffer_float' ); - function WebVRManager( renderer ) { + } - var scope = this; + return internalFormat; - var device = null; - var frameData = null; + } - var poseTarget = null; + // Fallback filters for non-power-of-2 textures - var controllers = []; - var standingMatrix = new Matrix4(); - var standingMatrixInverse = new Matrix4(); + function filterFallback( f ) { - var framebufferScaleFactor = 1.0; + if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - var frameOfReferenceType = 'stage'; + return 9728; - if ( typeof window !== 'undefined' && 'VRFrameData' in window ) { + } - frameData = new window.VRFrameData(); - window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false ); + return 9729; } - var matrixWorldInverse = new Matrix4(); - var tempQuaternion = new Quaternion(); - var tempPosition = new Vector3(); - - var cameraL = new PerspectiveCamera(); - cameraL.bounds = new Vector4( 0.0, 0.0, 0.5, 1.0 ); - cameraL.layers.enable( 1 ); - - var cameraR = new PerspectiveCamera(); - cameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 ); - cameraR.layers.enable( 2 ); - - var cameraVR = new ArrayCamera( [ cameraL, cameraR ] ); - cameraVR.layers.enable( 1 ); - cameraVR.layers.enable( 2 ); - // - function isPresenting() { - - return device !== null && device.isPresenting === true; - - } + function onTextureDispose( event ) { - var currentSize, currentPixelRatio; + var texture = event.target; - function onVRDisplayPresentChange() { + texture.removeEventListener( 'dispose', onTextureDispose ); - if ( isPresenting() ) { + deallocateTexture( texture ); - var eyeParameters = device.getEyeParameters( 'left' ); - var renderWidth = eyeParameters.renderWidth * framebufferScaleFactor; - var renderHeight = eyeParameters.renderHeight * framebufferScaleFactor; + if ( texture.isVideoTexture ) { - currentPixelRatio = renderer.getPixelRatio(); - currentSize = renderer.getSize(); + _videoTextures.delete( texture ); - renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 ); + } - animation.start(); + info.memory.textures --; - } else { + } - if ( scope.enabled ) { + function onRenderTargetDispose( event ) { - renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio ); + var renderTarget = event.target; - } + renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); - animation.stop(); + deallocateRenderTarget( renderTarget ); - } + info.memory.textures --; } // - var triggers = []; - - function findGamepad( id ) { + function deallocateTexture( texture ) { - var gamepads = navigator.getGamepads && navigator.getGamepads(); + var textureProperties = properties.get( texture ); - for ( var i = 0, j = 0, l = gamepads.length; i < l; i ++ ) { + if ( textureProperties.__webglInit === undefined ) { return; } - var gamepad = gamepads[ i ]; + _gl.deleteTexture( textureProperties.__webglTexture ); - if ( gamepad && ( gamepad.id === 'Daydream Controller' || - gamepad.id === 'Gear VR Controller' || gamepad.id === 'Oculus Go Controller' || - gamepad.id === 'OpenVR Gamepad' || gamepad.id.startsWith( 'Oculus Touch' ) || - gamepad.id.startsWith( 'Spatial Controller' ) ) ) { + properties.remove( texture ); - if ( j === id ) return gamepad; + } - j ++; + function deallocateRenderTarget( renderTarget ) { - } + var renderTargetProperties = properties.get( renderTarget ); + var textureProperties = properties.get( renderTarget.texture ); - } + if ( ! renderTarget ) { return; } - } + if ( textureProperties.__webglTexture !== undefined ) { - function updateControllers() { + _gl.deleteTexture( textureProperties.__webglTexture ); - for ( var i = 0; i < controllers.length; i ++ ) { + } - var controller = controllers[ i ]; + if ( renderTarget.depthTexture ) { - var gamepad = findGamepad( i ); + renderTarget.depthTexture.dispose(); - if ( gamepad !== undefined && gamepad.pose !== undefined ) { + } - if ( gamepad.pose === null ) return; + if ( renderTarget.isWebGLCubeRenderTarget ) { - // Pose + for ( var i = 0; i < 6; i ++ ) { - var pose = gamepad.pose; + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + if ( renderTargetProperties.__webglDepthbuffer ) { _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); } - if ( pose.hasPosition === false ) controller.position.set( 0.2, - 0.6, - 0.05 ); + } - if ( pose.position !== null ) controller.position.fromArray( pose.position ); - if ( pose.orientation !== null ) controller.quaternion.fromArray( pose.orientation ); - controller.matrix.compose( controller.position, controller.quaternion, controller.scale ); - controller.matrix.premultiply( standingMatrix ); - controller.matrix.decompose( controller.position, controller.quaternion, controller.scale ); - controller.matrixWorldNeedsUpdate = true; - controller.visible = true; + } else { - // Trigger + _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 ); } - var buttonId = gamepad.id === 'Daydream Controller' ? 0 : 1; + } - if ( triggers[ i ] !== gamepad.buttons[ buttonId ].pressed ) { + properties.remove( renderTarget.texture ); + properties.remove( renderTarget ); - triggers[ i ] = gamepad.buttons[ buttonId ].pressed; + } - if ( triggers[ i ] === true ) { + // - controller.dispatchEvent( { type: 'selectstart' } ); + var textureUnits = 0; - } else { + function resetTextureUnits() { - controller.dispatchEvent( { type: 'selectend' } ); - controller.dispatchEvent( { type: 'select' } ); + textureUnits = 0; - } + } - } + function allocateTextureUnit() { - } else { + var textureUnit = textureUnits; - controller.visible = false; + if ( textureUnit >= maxTextures ) { - } + console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures ); } - } - - // + textureUnits += 1; - this.enabled = false; + return textureUnit; - this.getController = function ( id ) { + } - var controller = controllers[ id ]; + // - if ( controller === undefined ) { + function setTexture2D( texture, slot ) { - controller = new Group(); - controller.matrixAutoUpdate = false; - controller.visible = false; + var textureProperties = properties.get( texture ); - controllers[ id ] = controller; + if ( texture.isVideoTexture ) { updateVideoTexture( texture ); } - } + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - return controller; + var image = texture.image; - }; + if ( image === undefined ) { - this.getDevice = function () { + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is undefined' ); - return device; + } else if ( image.complete === false ) { - }; + console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); - this.setDevice = function ( value ) { + } else { - if ( value !== undefined ) device = value; + uploadTexture( textureProperties, texture, slot ); + return; - animation.setContext( value ); + } - }; + } - this.setFramebufferScaleFactor = function ( value ) { + state.activeTexture( 33984 + slot ); + state.bindTexture( 3553, textureProperties.__webglTexture ); - framebufferScaleFactor = value; + } - }; + function setTexture2DArray( texture, slot ) { - this.setFrameOfReferenceType = function ( value ) { + var textureProperties = properties.get( texture ); - frameOfReferenceType = value; + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - }; + uploadTexture( textureProperties, texture, slot ); + return; - this.setPoseTarget = function ( object ) { + } - if ( object !== undefined ) poseTarget = object; + state.activeTexture( 33984 + slot ); + state.bindTexture( 35866, textureProperties.__webglTexture ); - }; + } - this.getCamera = function ( camera ) { + function setTexture3D( texture, slot ) { - var userHeight = frameOfReferenceType === 'stage' ? 1.6 : 0; + var textureProperties = properties.get( texture ); - if ( device === null ) { + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - camera.position.set( 0, userHeight, 0 ); - return camera; + uploadTexture( textureProperties, texture, slot ); + return; } - device.depthNear = camera.near; - device.depthFar = camera.far; + state.activeTexture( 33984 + slot ); + state.bindTexture( 32879, textureProperties.__webglTexture ); - device.getFrameData( frameData ); + } - // + function setTextureCube( texture, slot ) { - if ( frameOfReferenceType === 'stage' ) { + if ( texture.image.length !== 6 ) { return; } - var stageParameters = device.stageParameters; + var textureProperties = properties.get( texture ); - if ( stageParameters ) { + if ( texture.version > 0 && textureProperties.__version !== texture.version ) { - standingMatrix.fromArray( stageParameters.sittingToStandingTransform ); + initTexture( textureProperties, texture ); - } else { + state.activeTexture( 33984 + slot ); + state.bindTexture( 34067, textureProperties.__webglTexture ); - standingMatrix.makeTranslation( 0, userHeight, 0 ); + _gl.pixelStorei( 37440, texture.flipY ); - } + var isCompressed = ( texture && ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ) ); + var isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); - } + var cubeImage = []; + for ( var i = 0; i < 6; i ++ ) { - var pose = frameData.pose; - var poseObject = poseTarget !== null ? poseTarget : camera; + if ( ! isCompressed && ! isDataTexture ) { - // We want to manipulate poseObject by its position and quaternion components since users may rely on them. - poseObject.matrix.copy( standingMatrix ); - poseObject.matrix.decompose( poseObject.position, poseObject.quaternion, poseObject.scale ); + cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize ); - if ( pose.orientation !== null ) { + } else { - tempQuaternion.fromArray( pose.orientation ); - poseObject.quaternion.multiply( tempQuaternion ); + cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; - } + } - if ( pose.position !== null ) { + } - tempQuaternion.setFromRotationMatrix( standingMatrix ); - tempPosition.fromArray( pose.position ); - tempPosition.applyQuaternion( tempQuaternion ); - poseObject.position.add( tempPosition ); + var image = cubeImage[ 0 ], + supportsMips = isPowerOfTwo( image ) || isWebGL2, + glFormat = utils.convert( texture.format ), + glType = utils.convert( texture.type ), + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType ); - } + setTextureParameters( 34067, texture, supportsMips ); - poseObject.updateMatrixWorld(); + var mipmaps; - if ( device.isPresenting === false ) return camera; + if ( isCompressed ) { - // + for ( var i$1 = 0; i$1 < 6; i$1 ++ ) { - cameraL.near = camera.near; - cameraR.near = camera.near; + mipmaps = cubeImage[ i$1 ].mipmaps; - cameraL.far = camera.far; - cameraR.far = camera.far; + for ( var j = 0; j < mipmaps.length; j ++ ) { - cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix ); - cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix ); + var mipmap = mipmaps[ j ]; - // TODO (mrdoob) Double check this code + if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { - standingMatrixInverse.getInverse( standingMatrix ); + if ( glFormat !== null ) { - if ( frameOfReferenceType === 'stage' ) { + state.compressedTexImage2D( 34069 + i$1, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - cameraL.matrixWorldInverse.multiply( standingMatrixInverse ); - cameraR.matrixWorldInverse.multiply( standingMatrixInverse ); + } else { - } + console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); - var parent = poseObject.parent; + } - if ( parent !== null ) { + } else { - matrixWorldInverse.getInverse( parent.matrixWorld ); + state.texImage2D( 34069 + i$1, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - cameraL.matrixWorldInverse.multiply( matrixWorldInverse ); - cameraR.matrixWorldInverse.multiply( matrixWorldInverse ); + } - } + } - // envMap and Mirror needs camera.matrixWorld + } - cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse ); - cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse ); + textureProperties.__maxMipLevel = mipmaps.length - 1; - cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix ); - cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix ); + } else { - setProjectionFromUnion( cameraVR, cameraL, cameraR ); + mipmaps = texture.mipmaps; - // + for ( var i$2 = 0; i$2 < 6; i$2 ++ ) { - var layers = device.getLayers(); + if ( isDataTexture ) { - if ( layers.length ) { + state.texImage2D( 34069 + i$2, 0, glInternalFormat, cubeImage[ i$2 ].width, cubeImage[ i$2 ].height, 0, glFormat, glType, cubeImage[ i$2 ].data ); - var layer = layers[ 0 ]; + for ( var j$1 = 0; j$1 < mipmaps.length; j$1 ++ ) { - if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) { + var mipmap$1 = mipmaps[ j$1 ]; + var mipmapImage = mipmap$1.image[ i$2 ].image; - cameraL.bounds.fromArray( layer.leftBounds ); + state.texImage2D( 34069 + i$2, j$1 + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); - } + } - if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) { + } else { - cameraR.bounds.fromArray( layer.rightBounds ); + state.texImage2D( 34069 + i$2, 0, glInternalFormat, glFormat, glType, cubeImage[ i$2 ] ); - } + for ( var j$2 = 0; j$2 < mipmaps.length; j$2 ++ ) { - } + var mipmap$2 = mipmaps[ j$2 ]; - updateControllers(); + state.texImage2D( 34069 + i$2, j$2 + 1, glInternalFormat, glFormat, glType, mipmap$2.image[ i$2 ] ); - return cameraVR; + } - }; + } - this.getStandingMatrix = function () { + } - return standingMatrix; + textureProperties.__maxMipLevel = mipmaps.length; - }; + } - this.isPresenting = isPresenting; + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - // Animation Loop + // We assume images for cube map have the same size. + generateMipmap( 34067, texture, image.width, image.height ); - var animation = new WebGLAnimation(); + } - this.setAnimationLoop = function ( callback ) { + textureProperties.__version = texture.version; - animation.setAnimationLoop( callback ); + if ( texture.onUpdate ) { texture.onUpdate( texture ); } - }; + } else { - this.submitFrame = function () { + state.activeTexture( 33984 + slot ); + state.bindTexture( 34067, textureProperties.__webglTexture ); - if ( isPresenting() ) device.submitFrame(); + } - }; + } - this.dispose = function () { + function setTextureCubeDynamic( texture, slot ) { - if ( typeof window !== 'undefined' ) { + state.activeTexture( 33984 + slot ); + state.bindTexture( 34067, properties.get( texture ).__webglTexture ); - window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange ); + } - } + var wrappingToGL = {}; + wrappingToGL[ RepeatWrapping ] = 10497; + wrappingToGL[ ClampToEdgeWrapping ] = 33071; + wrappingToGL[ MirroredRepeatWrapping ] = 33648; - }; + var filterToGL = {}; + filterToGL[ NearestFilter ] = 9728; + filterToGL[ NearestMipmapNearestFilter ] = 9984; + filterToGL[ NearestMipmapLinearFilter ] = 9986; + filterToGL[ LinearFilter ] = 9729; + filterToGL[ LinearMipmapNearestFilter ] = 9985; + filterToGL[ LinearMipmapLinearFilter ] = 9987; - } + function setTextureParameters( textureType, texture, supportsMips ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + if ( supportsMips ) { - function WebXRManager( renderer ) { + _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] ); + _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] ); - var gl = renderer.context; + if ( textureType === 32879 || textureType === 35866 ) { - var device = null; - var session = null; + _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] ); - var framebufferScaleFactor = 1.0; + } - var frameOfReference = null; - var frameOfReferenceType = 'stage'; + _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] ); + _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] ); - var pose = null; + } else { - var controllers = []; - var inputSources = []; + _gl.texParameteri( textureType, 10242, 33071 ); + _gl.texParameteri( textureType, 10243, 33071 ); - function isPresenting() { + if ( textureType === 32879 || textureType === 35866 ) { - return session !== null && frameOfReference !== null; + _gl.texParameteri( textureType, 32882, 33071 ); - } + } - // + if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { - var cameraL = new PerspectiveCamera(); - cameraL.layers.enable( 1 ); - cameraL.viewport = new Vector4(); + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); - var cameraR = new PerspectiveCamera(); - cameraR.layers.enable( 2 ); - cameraR.viewport = new Vector4(); + } - var cameraVR = new ArrayCamera( [ cameraL, cameraR ] ); - cameraVR.layers.enable( 1 ); - cameraVR.layers.enable( 2 ); + _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); - // + if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { - this.enabled = false; + console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); - this.getController = function ( id ) { + } - var controller = controllers[ id ]; + } - if ( controller === undefined ) { + var extension = extensions.get( 'EXT_texture_filter_anisotropic' ); - controller = new Group(); - controller.matrixAutoUpdate = false; - controller.visible = false; + if ( extension ) { - controllers[ id ] = controller; + if ( texture.type === FloatType && extensions.get( 'OES_texture_float_linear' ) === null ) { return; } + if ( texture.type === HalfFloatType && ( isWebGL2 || extensions.get( 'OES_texture_half_float_linear' ) ) === null ) { return; } - } + if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { - return controller; + _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); + properties.get( texture ).__currentAnisotropy = texture.anisotropy; - }; + } - this.getDevice = function () { + } - return device; + } - }; + function initTexture( textureProperties, texture ) { - this.setDevice = function ( value ) { + if ( textureProperties.__webglInit === undefined ) { - if ( value !== undefined ) device = value; - if ( value instanceof XRDevice ) gl.setCompatibleXRDevice( value ); + textureProperties.__webglInit = true; - }; + texture.addEventListener( 'dispose', onTextureDispose ); - // + textureProperties.__webglTexture = _gl.createTexture(); - function onSessionEvent( event ) { + info.memory.textures ++; - var controller = controllers[ inputSources.indexOf( event.inputSource ) ]; - if ( controller ) controller.dispatchEvent( { type: event.type } ); + } } - function onSessionEnd() { - - renderer.setFramebuffer( null ); - animation.stop(); + function uploadTexture( textureProperties, texture, slot ) { - } + var textureType = 3553; - this.setFramebufferScaleFactor = function ( value ) { + if ( texture.isDataTexture2DArray ) { textureType = 35866; } + if ( texture.isDataTexture3D ) { textureType = 32879; } - framebufferScaleFactor = value; + initTexture( textureProperties, texture ); - }; + state.activeTexture( 33984 + slot ); + state.bindTexture( textureType, textureProperties.__webglTexture ); - this.setFrameOfReferenceType = function ( value ) { + _gl.pixelStorei( 37440, texture.flipY ); + _gl.pixelStorei( 37441, texture.premultiplyAlpha ); + _gl.pixelStorei( 3317, texture.unpackAlignment ); - frameOfReferenceType = value; + var needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false; + var image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize ); - }; + var supportsMips = isPowerOfTwo( image ) || isWebGL2, + glFormat = utils.convert( texture.format ); - this.setSession = function ( value ) { + var glType = utils.convert( texture.type ), + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType ); - session = value; + setTextureParameters( textureType, texture, supportsMips ); - if ( session !== null ) { + var mipmap; + var mipmaps = texture.mipmaps; - session.addEventListener( 'select', onSessionEvent ); - session.addEventListener( 'selectstart', onSessionEvent ); - session.addEventListener( 'selectend', onSessionEvent ); - session.addEventListener( 'end', onSessionEnd ); + if ( texture.isDepthTexture ) { - session.baseLayer = new XRWebGLLayer( session, gl, { framebufferScaleFactor: framebufferScaleFactor } ); - session.requestFrameOfReference( frameOfReferenceType ).then( function ( value ) { + // populate depth texture with dummy data - frameOfReference = value; + glInternalFormat = 6402; - renderer.setFramebuffer( session.baseLayer.framebuffer ); + if ( isWebGL2 ) { - animation.setContext( session ); - animation.start(); + if ( texture.type === FloatType ) { - } ); + glInternalFormat = 36012; - // + } else if ( texture.type === UnsignedIntType ) { - inputSources = session.getInputSources(); + glInternalFormat = 33190; - session.addEventListener( 'inputsourceschange', function () { + } else if ( texture.type === UnsignedInt248Type ) { - inputSources = session.getInputSources(); - console.log( inputSources ); + glInternalFormat = 35056; - for ( var i = 0; i < controllers.length; i ++ ) { + } else { - var controller = controllers[ i ]; - controller.userData.inputSource = inputSources[ i ]; + glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D } - } ); + } else { - } + if ( texture.type === FloatType ) { - }; + console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' ); - function updateCamera( camera, parent ) { + } - if ( parent === null ) { + } - camera.matrixWorld.copy( camera.matrix ); + // validation checks for WebGL 1 - } else { + if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { - camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); + // 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.' ); - camera.matrixWorldInverse.getInverse( camera.matrixWorld ); + texture.type = UnsignedShortType; + glType = utils.convert( texture.type ); - } + } - this.getCamera = function ( camera ) { + } + + if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) { - if ( isPresenting() ) { + // Depth stencil textures need the DEPTH_STENCIL internal format + // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) + glInternalFormat = 34041; - var parent = camera.parent; - var cameras = cameraVR.cameras; + // 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 ) { - updateCamera( cameraVR, parent ); + console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); - for ( var i = 0; i < cameras.length; i ++ ) { + texture.type = UnsignedInt248Type; + glType = utils.convert( texture.type ); - updateCamera( cameras[ i ], parent ); + } } - // update camera and its children + // - camera.matrixWorld.copy( cameraVR.matrixWorld ); + state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); - var children = camera.children; + } else if ( texture.isDataTexture ) { - for ( var i = 0, l = children.length; i < l; i ++ ) { + // 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 - children[ i ].updateMatrixWorld( true ); + if ( mipmaps.length > 0 && supportsMips ) { - } + for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { - setProjectionFromUnion( cameraVR, cameraL, cameraR ); + mipmap = mipmaps[ i ]; + state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); - return cameraVR; + } - } + texture.generateMipmaps = false; + textureProperties.__maxMipLevel = mipmaps.length - 1; - return camera; + } else { - }; + state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); + textureProperties.__maxMipLevel = 0; - this.isPresenting = isPresenting; + } - // Animation Loop + } else if ( texture.isCompressedTexture ) { - var onAnimationFrameCallback = null; + for ( var i$1 = 0, il$1 = mipmaps.length; i$1 < il$1; i$1 ++ ) { - function onAnimationFrame( time, frame ) { + mipmap = mipmaps[ i$1 ]; - pose = frame.getDevicePose( frameOfReference ); + if ( texture.format !== RGBAFormat && texture.format !== RGBFormat ) { - if ( pose !== null ) { + if ( glFormat !== null ) { - var layer = session.baseLayer; - var views = frame.views; + state.compressedTexImage2D( 3553, i$1, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); - for ( var i = 0; i < views.length; i ++ ) { + } else { - var view = views[ i ]; - var viewport = layer.getViewport( view ); - var viewMatrix = pose.getViewMatrix( view ); + console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); - var camera = cameraVR.cameras[ i ]; - camera.matrix.fromArray( viewMatrix ).getInverse( camera.matrix ); - camera.projectionMatrix.fromArray( view.projectionMatrix ); - camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); + } - if ( i === 0 ) { + } else { - cameraVR.matrix.copy( camera.matrix ); + state.texImage2D( 3553, i$1, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } } - } + textureProperties.__maxMipLevel = mipmaps.length - 1; - // + } else if ( texture.isDataTexture2DArray ) { - for ( var i = 0; i < controllers.length; i ++ ) { + state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + textureProperties.__maxMipLevel = 0; - var controller = controllers[ i ]; + } else if ( texture.isDataTexture3D ) { - var inputSource = inputSources[ i ]; + state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + textureProperties.__maxMipLevel = 0; - if ( inputSource ) { + } else { - var inputPose = frame.getInputPose( inputSource, frameOfReference ); + // regular Texture (image, video, canvas) - if ( inputPose !== null ) { + // 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 ( 'targetRay' in inputPose ) { + if ( mipmaps.length > 0 && supportsMips ) { - controller.matrix.elements = inputPose.targetRay.transformMatrix; + for ( var i$2 = 0, il$2 = mipmaps.length; i$2 < il$2; i$2 ++ ) { - } else if ( 'pointerMatrix' in inputPose ) { + mipmap = mipmaps[ i$2 ]; + state.texImage2D( 3553, i$2, glInternalFormat, glFormat, glType, mipmap ); - // DEPRECATED + } - controller.matrix.elements = inputPose.pointerMatrix; + texture.generateMipmaps = false; + textureProperties.__maxMipLevel = mipmaps.length - 1; - } + } else { - controller.matrix.decompose( controller.position, controller.rotation, controller.scale ); - controller.visible = true; + state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); + textureProperties.__maxMipLevel = 0; - continue; + } - } + } - } + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - controller.visible = false; + generateMipmap( textureType, texture, image.width, image.height ); } - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); + textureProperties.__version = texture.version; + + if ( texture.onUpdate ) { texture.onUpdate( texture ); } } - var animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); + // Render targets - this.setAnimationLoop = function ( callback ) { + // Setup storage for target texture and bind it to correct framebuffer + function setupFrameBufferTexture( framebuffer, renderTarget, attachment, textureTarget ) { - onAnimationFrameCallback = callback; + var glFormat = utils.convert( renderTarget.texture.format ); + var glType = utils.convert( renderTarget.texture.type ); + var glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType ); + state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + _gl.bindFramebuffer( 36160, framebuffer ); + _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( renderTarget.texture ).__webglTexture, 0 ); + _gl.bindFramebuffer( 36160, null ); - }; + } - this.dispose = function () {}; + // Setup storage for internal depth/stencil buffers and bind to correct framebuffer + function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { - // DEPRECATED + _gl.bindRenderbuffer( 36161, renderbuffer ); - this.getStandingMatrix = function () { + if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - console.warn( 'THREE.WebXRManager: getStandingMatrix() is no longer needed.' ); - return new THREE.Matrix4(); + var glInternalFormat = 33189; - }; + if ( isMultisample ) { - this.submitFrame = function () {}; + var depthTexture = renderTarget.depthTexture; - } + if ( depthTexture && depthTexture.isDepthTexture ) { - /** - * @author supereggbert / http://www.paulbrunt.co.uk/ - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * @author szimek / https://github.com/szimek/ - * @author tschw - */ + if ( depthTexture.type === FloatType ) { - function WebGLRenderer( parameters ) { + glInternalFormat = 36012; - console.log( 'THREE.WebGLRenderer', REVISION ); + } else if ( depthTexture.type === UnsignedIntType ) { - parameters = parameters || {}; + glInternalFormat = 33190; - var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ), - _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'; + } - var currentRenderList = null; - var currentRenderState = null; + var samples = getRenderTargetSamples( renderTarget ); - // public properties + _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - this.domElement = _canvas; - this.context = null; + } else { - // clearing + _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; + } - // scene graph + _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); - this.sortObjects = true; + } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { - // user-defined clipping + if ( isMultisample ) { - this.clippingPlanes = []; - this.localClippingEnabled = false; + var samples$1 = getRenderTargetSamples( renderTarget ); - // physically based shading + _gl.renderbufferStorageMultisample( 36161, samples$1, 35056, renderTarget.width, renderTarget.height ); - this.gammaFactor = 2.0; // for backwards compatibility - this.gammaInput = false; - this.gammaOutput = false; + } else { - // physical lights + _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); - this.physicallyCorrectLights = false; + } - // tone mapping - this.toneMapping = LinearToneMapping; - this.toneMappingExposure = 1.0; - this.toneMappingWhitePoint = 1.0; + _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); - // morphs + } else { - this.maxMorphTargets = 8; - this.maxMorphNormals = 4; + var glFormat = utils.convert( renderTarget.texture.format ); + var glType = utils.convert( renderTarget.texture.type ); + var glInternalFormat$1 = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType ); - // internal properties + if ( isMultisample ) { - var _this = this, + var samples$2 = getRenderTargetSamples( renderTarget ); - _isContextLost = false, + _gl.renderbufferStorageMultisample( 36161, samples$2, glInternalFormat$1, renderTarget.width, renderTarget.height ); - // internal state cache + } else { - _framebuffer = null, + _gl.renderbufferStorage( 36161, glInternalFormat$1, renderTarget.width, renderTarget.height ); - _currentRenderTarget = null, - _currentFramebuffer = null, - _currentMaterialId = - 1, + } - // geometry and program caching + } - _currentGeometryProgram = { - geometry: null, - program: null, - wireframe: false - }, + _gl.bindRenderbuffer( 36161, null ); - _currentCamera = null, - _currentArrayCamera = null, + } - _currentViewport = new Vector4(), - _currentScissor = new Vector4(), - _currentScissorTest = null, + // Setup resources for a Depth Texture for a FBO (needs an extension) + function setupDepthTexture( framebuffer, renderTarget ) { - // + var isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); + if ( isCube ) { throw new Error( 'Depth Texture with cube render targets is not supported' ); } - _usedTextureUnits = 0, + _gl.bindFramebuffer( 36160, framebuffer ); - // + if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { - _width = _canvas.width, - _height = _canvas.height, + throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); - _pixelRatio = 1, + } - _viewport = new Vector4( 0, 0, _width, _height ), - _scissor = new Vector4( 0, 0, _width, _height ), - _scissorTest = false, + // 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 ) { - // frustum + renderTarget.depthTexture.image.width = renderTarget.width; + renderTarget.depthTexture.image.height = renderTarget.height; + renderTarget.depthTexture.needsUpdate = true; - _frustum = new Frustum(), + } - // clipping + setTexture2D( renderTarget.depthTexture, 0 ); - _clipping = new WebGLClipping(), - _clippingEnabled = false, - _localClippingEnabled = false, + var webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; - // camera matrices cache + if ( renderTarget.depthTexture.format === DepthFormat ) { - _projScreenMatrix = new Matrix4(), + _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); - _vector3 = new Vector3(); + } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { - function getTargetPixelRatio() { + _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); - return _currentRenderTarget === null ? _pixelRatio : 1; + } else { - } + throw new Error( 'Unknown depthTexture format' ); - // initialize + } - var _gl; + } - try { + // Setup GL resources for a non-texture depth buffer + function setupDepthRenderbuffer( renderTarget ) { - var contextAttributes = { - alpha: _alpha, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer, - powerPreference: _powerPreference - }; + var renderTargetProperties = properties.get( renderTarget ); - // event listeners must be registered before WebGL context is created, see #12753 + var isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); - _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - - _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes ); - - if ( _gl === null ) { + if ( renderTarget.depthTexture ) { - if ( _canvas.getContext( 'webgl' ) !== null ) { + if ( isCube ) { throw new Error( 'target.depthTexture not supported in Cube render targets' ); } - throw new Error( 'Error creating WebGL context with your selected attributes.' ); + setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); - } else { + } else { - throw new Error( 'Error creating WebGL context.' ); + if ( isCube ) { - } + renderTargetProperties.__webglDepthbuffer = []; - } + for ( var i = 0; i < 6; i ++ ) { - // Some experimental-webgl implementations do not have getShaderPrecisionFormat + _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); + renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); - if ( _gl.getShaderPrecisionFormat === undefined ) { + } - _gl.getShaderPrecisionFormat = function () { + } else { - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + _gl.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); + renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); - }; + } } - } catch ( error ) { - - console.error( 'THREE.WebGLRenderer: ' + error.message ); + _gl.bindFramebuffer( 36160, null ); } - var extensions, capabilities, state, info; - var properties, textures, attributes, geometries, objects; - var programCache, renderLists, renderStates; + // Set up GL resources for the render target + function setupRenderTarget( renderTarget ) { - var background, morphtargets, bufferRenderer, indexedBufferRenderer; + var renderTargetProperties = properties.get( renderTarget ); + var textureProperties = properties.get( renderTarget.texture ); - var utils; + renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); - function initGLContext() { + textureProperties.__webglTexture = _gl.createTexture(); - extensions = new WebGLExtensions( _gl ); + info.memory.textures ++; - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); + var isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); + var isMultisample = ( renderTarget.isWebGLMultisampleRenderTarget === true ); + var supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2; - if ( ! capabilities.isWebGL2 ) { + // Handles WebGL2 RGBFormat fallback - #18858 - extensions.get( 'WEBGL_depth_texture' ); - extensions.get( 'OES_texture_float' ); - extensions.get( 'OES_texture_half_float' ); - extensions.get( 'OES_texture_half_float_linear' ); - extensions.get( 'OES_standard_derivatives' ); - extensions.get( 'OES_element_index_uint' ); - extensions.get( 'ANGLE_instanced_arrays' ); + if ( isWebGL2 && renderTarget.texture.format === RGBFormat && ( renderTarget.texture.type === FloatType || renderTarget.texture.type === HalfFloatType ) ) { - } + renderTarget.texture.format = RGBAFormat; - extensions.get( 'OES_texture_float_linear' ); + console.warn( 'THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.' ); - utils = new WebGLUtils( _gl, extensions, capabilities ); + } - state = new WebGLState( _gl, extensions, utils, capabilities ); - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); + // Setup framebuffer - info = new WebGLInfo( _gl ); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); - attributes = new WebGLAttributes( _gl ); - geometries = new WebGLGeometries( _gl, attributes, info ); - objects = new WebGLObjects( geometries, info ); - morphtargets = new WebGLMorphtargets( _gl ); - programCache = new WebGLPrograms( _this, extensions, capabilities ); - renderLists = new WebGLRenderLists(); - renderStates = new WebGLRenderStates(); + if ( isCube ) { - background = new WebGLBackground( _this, state, objects, _premultipliedAlpha ); + renderTargetProperties.__webglFramebuffer = []; - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); + for ( var i = 0; i < 6; i ++ ) { - info.programs = programCache.programs; + renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); - _this.context = _gl; - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.state = state; - _this.info = info; + } - } + } else { - initGLContext(); + renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); - // vr + if ( isMultisample ) { - var vr = null; + if ( isWebGL2 ) { - if ( typeof navigator !== 'undefined' ) { + renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); + renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer(); - vr = ( 'xr' in navigator ) ? new WebXRManager( _this ) : new WebVRManager( _this ); + _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer ); - } + var glFormat = utils.convert( renderTarget.texture.format ); + var glType = utils.convert( renderTarget.texture.type ); + var glInternalFormat = getInternalFormat( renderTarget.texture.internalFormat, glFormat, glType ); + var samples = getRenderTargetSamples( renderTarget ); + _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - this.vr = vr; + _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); + _gl.framebufferRenderbuffer( 36160, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer ); + _gl.bindRenderbuffer( 36161, null ); - // shadow map + if ( renderTarget.depthBuffer ) { - var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize ); + renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); + setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true ); - this.shadowMap = shadowMap; + } - // API + _gl.bindFramebuffer( 36160, null ); - this.getContext = function () { - return _gl; + } else { - }; + console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' ); - this.getContextAttributes = function () { + } - return _gl.getContextAttributes(); + } - }; + } - this.forceContextLoss = function () { + // Setup color buffer - var extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); + if ( isCube ) { - }; + state.bindTexture( 34067, textureProperties.__webglTexture ); + setTextureParameters( 34067, renderTarget.texture, supportsMips ); - this.forceContextRestore = function () { + for ( var i$1 = 0; i$1 < 6; i$1 ++ ) { - var extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i$1 ], renderTarget, 36064, 34069 + i$1 ); - }; + } - this.getPixelRatio = function () { + if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) { - return _pixelRatio; + generateMipmap( 34067, renderTarget.texture, renderTarget.width, renderTarget.height ); - }; + } - this.setPixelRatio = function ( value ) { + state.bindTexture( 34067, null ); - if ( value === undefined ) return; + } else { - _pixelRatio = value; + state.bindTexture( 3553, textureProperties.__webglTexture ); + setTextureParameters( 3553, renderTarget.texture, supportsMips ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, 36064, 3553 ); - this.setSize( _width, _height, false ); + if ( textureNeedsGenerateMipmaps( renderTarget.texture, supportsMips ) ) { - }; + generateMipmap( 3553, renderTarget.texture, renderTarget.width, renderTarget.height ); - this.getSize = function () { + } - return { - width: _width, - height: _height - }; + state.bindTexture( 3553, null ); - }; + } - this.setSize = function ( width, height, updateStyle ) { + // Setup depth and stencil buffers - if ( vr.isPresenting() ) { + if ( renderTarget.depthBuffer ) { - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; + setupDepthRenderbuffer( renderTarget ); } - _width = width; - _height = height; - - _canvas.width = width * _pixelRatio; - _canvas.height = height * _pixelRatio; - - if ( updateStyle !== false ) { + } - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; + function updateRenderTargetMipmap( renderTarget ) { - } + var texture = renderTarget.texture; + var supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2; - this.setViewport( 0, 0, width, height ); + if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - }; + var target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553; + var webglTexture = properties.get( texture ).__webglTexture; - this.getDrawingBufferSize = function () { + state.bindTexture( target, webglTexture ); + generateMipmap( target, texture, renderTarget.width, renderTarget.height ); + state.bindTexture( target, null ); - return { - width: _width * _pixelRatio, - height: _height * _pixelRatio - }; + } - }; + } - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { + function updateMultisampleRenderTarget( renderTarget ) { - _width = width; - _height = height; + if ( renderTarget.isWebGLMultisampleRenderTarget ) { - _pixelRatio = pixelRatio; + if ( isWebGL2 ) { - _canvas.width = width * pixelRatio; - _canvas.height = height * pixelRatio; + var renderTargetProperties = properties.get( renderTarget ); - this.setViewport( 0, 0, width, height ); + _gl.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer ); + _gl.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer ); - }; + var width = renderTarget.width; + var height = renderTarget.height; + var mask = 16384; - this.getCurrentViewport = function () { + if ( renderTarget.depthBuffer ) { mask |= 256; } + if ( renderTarget.stencilBuffer ) { mask |= 1024; } - return _currentViewport; + _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 ); - }; + _gl.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); // see #18905 - this.setViewport = function ( x, y, width, height ) { + } else { - _viewport.set( x, _height - y - height, width, height ); - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ) ); + console.warn( 'THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.' ); - }; + } - this.setScissor = function ( x, y, width, height ) { + } - _scissor.set( x, _height - y - height, width, height ); - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ) ); + } - }; + function getRenderTargetSamples( renderTarget ) { - this.setScissorTest = function ( boolean ) { + return ( isWebGL2 && renderTarget.isWebGLMultisampleRenderTarget ) ? + Math.min( maxSamples, renderTarget.samples ) : 0; - state.setScissorTest( _scissorTest = boolean ); + } - }; + function updateVideoTexture( texture ) { - // Clearing + var frame = info.render.frame; - this.getClearColor = function () { + // Check the last frame we updated the VideoTexture - return background.getClearColor(); + if ( _videoTextures.get( texture ) !== frame ) { - }; + _videoTextures.set( texture, frame ); + texture.update(); - this.setClearColor = function () { + } - background.setClearColor.apply( background, arguments ); + } - }; + // backwards compatibility - this.getClearAlpha = function () { + var warnedTexture2D = false; + var warnedTextureCube = false; - return background.getClearAlpha(); + function safeSetTexture2D( texture, slot ) { - }; + if ( texture && texture.isWebGLRenderTarget ) { - this.setClearAlpha = function () { + if ( warnedTexture2D === false ) { - background.setClearAlpha.apply( background, arguments ); + console.warn( "THREE.WebGLTextures.safeSetTexture2D: don't use render targets as textures. Use their .texture property instead." ); + warnedTexture2D = true; - }; + } - this.clear = function ( color, depth, stencil ) { + texture = texture.texture; - var bits = 0; + } - if ( color === undefined || color ) bits |= 16384; - if ( depth === undefined || depth ) bits |= 256; - if ( stencil === undefined || stencil ) bits |= 1024; + setTexture2D( texture, slot ); - _gl.clear( bits ); + } - }; + function safeSetTextureCube( texture, slot ) { - this.clearColor = function () { + if ( texture && texture.isWebGLCubeRenderTarget ) { - this.clear( true, false, false ); + if ( warnedTextureCube === false ) { - }; + console.warn( "THREE.WebGLTextures.safeSetTextureCube: don't use cube render targets as textures. Use their .texture property instead." ); + warnedTextureCube = true; - this.clearDepth = function () { + } - this.clear( false, true, false ); + texture = texture.texture; - }; + } - this.clearStencil = function () { + // currently relying on the fact that WebGLCubeRenderTarget.texture is a Texture and NOT a CubeTexture + // TODO: unify these code paths + if ( ( texture && texture.isCubeTexture ) || + ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) { - this.clear( false, false, true ); + // CompressedTexture can have Array in image :/ - }; + // this function alone should take care of cube textures + setTextureCube( texture, slot ); - // + } else { - this.dispose = function () { + // assumed: texture property of THREE.WebGLCubeRenderTarget + setTextureCubeDynamic( texture, slot ); - _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); + } - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - objects.dispose(); + } - vr.dispose(); + // - animation.stop(); + this.allocateTextureUnit = allocateTextureUnit; + this.resetTextureUnits = resetTextureUnits; - }; + this.setTexture2D = setTexture2D; + this.setTexture2DArray = setTexture2DArray; + this.setTexture3D = setTexture3D; + this.setTextureCube = setTextureCube; + this.setTextureCubeDynamic = setTextureCubeDynamic; + this.setupRenderTarget = setupRenderTarget; + this.updateRenderTargetMipmap = updateRenderTargetMipmap; + this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; - // Events + this.safeSetTexture2D = safeSetTexture2D; + this.safeSetTextureCube = safeSetTextureCube; - function onContextLost( event ) { + } - event.preventDefault(); + function WebGLUtils( gl, extensions, capabilities ) { - console.log( 'THREE.WebGLRenderer: Context Lost.' ); + var isWebGL2 = capabilities.isWebGL2; - _isContextLost = true; + function convert( p ) { - } + var extension; - function onContextRestore( /* event */ ) { + if ( p === UnsignedByteType ) { return 5121; } + if ( p === UnsignedShort4444Type ) { return 32819; } + if ( p === UnsignedShort5551Type ) { return 32820; } + if ( p === UnsignedShort565Type ) { return 33635; } - console.log( 'THREE.WebGLRenderer: Context Restored.' ); + 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; } - _isContextLost = false; + if ( p === HalfFloatType ) { - initGLContext(); + if ( isWebGL2 ) { return 5131; } - } + extension = extensions.get( 'OES_texture_half_float' ); - function onMaterialDispose( event ) { + if ( extension !== null ) { - var material = event.target; + return extension.HALF_FLOAT_OES; - material.removeEventListener( 'dispose', onMaterialDispose ); + } else { - deallocateMaterial( material ); + return null; - } + } - // Buffer deallocation + } - function deallocateMaterial( material ) { + 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; } - releaseMaterialProgramReference( material ); + // WebGL2 formats. - properties.remove( material ); + 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' ); - function releaseMaterialProgramReference( material ) { + if ( extension !== null ) { - var programInfo = properties.get( material ).program; + 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; } - material.program = undefined; + } else { - if ( programInfo !== undefined ) { + return null; - programCache.releaseProgram( programInfo ); + } } - } + if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || + p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { - // Buffer rendering + extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); - function renderObjectImmediate( object, program ) { + if ( extension !== null ) { - object.render( function ( object ) { + 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; } - _this.renderBufferImmediate( object, program ); + } else { - } ); + return null; - } + } - this.renderBufferImmediate = function ( object, program ) { + } - state.initAttributes(); + if ( p === RGB_ETC1_Format ) { - var buffers = properties.get( object ); + extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); - 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(); + if ( extension !== null ) { - var programAttributes = program.getAttributes(); + return extension.COMPRESSED_RGB_ETC1_WEBGL; - if ( object.hasPositions ) { + } else { - _gl.bindBuffer( 34962, buffers.position ); - _gl.bufferData( 34962, object.positionArray, 35048 ); + return null; - state.enableAttribute( programAttributes.position ); - _gl.vertexAttribPointer( programAttributes.position, 3, 5126, false, 0, 0 ); + } } - if ( object.hasNormals ) { + if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) { - _gl.bindBuffer( 34962, buffers.normal ); - _gl.bufferData( 34962, object.normalArray, 35048 ); + extension = extensions.get( 'WEBGL_compressed_texture_etc' ); - state.enableAttribute( programAttributes.normal ); - _gl.vertexAttribPointer( programAttributes.normal, 3, 5126, false, 0, 0 ); + 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 ( object.hasUvs ) { + } - _gl.bindBuffer( 34962, buffers.uv ); - _gl.bufferData( 34962, object.uvArray, 35048 ); + } - state.enableAttribute( programAttributes.uv ); - _gl.vertexAttribPointer( programAttributes.uv, 2, 5126, false, 0, 0 ); + 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 ( object.hasColors ) { + if ( extension !== null ) { - _gl.bindBuffer( 34962, buffers.color ); - _gl.bufferData( 34962, object.colorArray, 35048 ); + // TODO Complete? - state.enableAttribute( programAttributes.color ); - _gl.vertexAttribPointer( programAttributes.color, 3, 5126, false, 0, 0 ); + return p; - } + } else { - state.disableUnusedAttributes(); + return null; - _gl.drawArrays( 4, 0, object.count ); + } - object.count = 0; + } - }; + if ( p === RGBA_BPTC_Format ) { - this.renderBufferDirect = function ( camera, fog, geometry, material, object, group ) { + extension = extensions.get( 'EXT_texture_compression_bptc' ); - var frontFaceCW = ( object.isMesh && object.normalMatrix.determinant() < 0 ); + if ( extension !== null ) { - state.setMaterial( material, frontFaceCW ); + // TODO Complete? - var program = setProgram( camera, fog, material, object ); + return p; - var updateBuffers = false; + } else { - if ( _currentGeometryProgram.geometry !== geometry.id || - _currentGeometryProgram.program !== program.id || - _currentGeometryProgram.wireframe !== ( material.wireframe === true ) ) { + return null; - _currentGeometryProgram.geometry = geometry.id; - _currentGeometryProgram.program = program.id; - _currentGeometryProgram.wireframe = material.wireframe === true; - updateBuffers = true; + } } - if ( object.morphTargetInfluences ) { + if ( p === UnsignedInt248Type ) { - morphtargets.update( object, geometry, material, program ); + if ( isWebGL2 ) { return 34042; } - updateBuffers = true; + extension = extensions.get( 'WEBGL_depth_texture' ); - } + if ( extension !== null ) { - // + return extension.UNSIGNED_INT_24_8_WEBGL; - var index = geometry.index; - var position = geometry.attributes.position; - var rangeFactor = 1; + } else { - if ( material.wireframe === true ) { + return null; - index = geometries.getWireframeAttribute( geometry ); - rangeFactor = 2; + } } - var attribute; - var renderer = bufferRenderer; - - if ( index !== null ) { + } - attribute = attributes.get( index ); + return { convert: convert }; - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); + } - } + function ArrayCamera( array ) { - if ( updateBuffers ) { + PerspectiveCamera.call( this ); - setupVertexAttributes( material, program, geometry ); + this.cameras = array || []; - if ( index !== null ) { + } - _gl.bindBuffer( 34963, attribute.buffer ); + ArrayCamera.prototype = Object.assign( Object.create( PerspectiveCamera.prototype ), { - } + constructor: ArrayCamera, - } + isArrayCamera: true - // + } ); - var dataCount = Infinity; + function Group() { - if ( index !== null ) { + Object3D.call( this ); - dataCount = index.count; + this.type = 'Group'; - } else if ( position !== undefined ) { + } - dataCount = position.count; + Group.prototype = Object.assign( Object.create( Object3D.prototype ), { - } + constructor: Group, - var rangeStart = geometry.drawRange.start * rangeFactor; - var rangeCount = geometry.drawRange.count * rangeFactor; + isGroup: true - var groupStart = group !== null ? group.start * rangeFactor : 0; - var groupCount = group !== null ? group.count * rangeFactor : Infinity; + } ); - var drawStart = Math.max( rangeStart, groupStart ); - var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; + function WebXRController() { - var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); + this._targetRay = null; + this._grip = null; + this._hand = null; - if ( drawCount === 0 ) return; + } - // + Object.assign( WebXRController.prototype, { - if ( object.isMesh ) { + constructor: WebXRController, - if ( material.wireframe === true ) { + getHandSpace: function () { - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( 1 ); + if ( this._hand === null ) { - } else { + this._hand = new Group(); + this._hand.matrixAutoUpdate = false; + this._hand.visible = false; - switch ( object.drawMode ) { + this._hand.joints = []; + this._hand.inputState = { pinching: false }; - case TrianglesDrawMode: - renderer.setMode( 4 ); - break; + if ( window.XRHand ) { - case TriangleStripDrawMode: - renderer.setMode( 5 ); - break; + for ( var i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) { - case TriangleFanDrawMode: - renderer.setMode( 6 ); - break; + // The transform of this joint will be updated with the joint pose on each frame + var joint = new Group(); + joint.matrixAutoUpdate = false; + joint.visible = false; + this._hand.joints.push( joint ); + // ?? + this._hand.add( joint ); } } + } - } else if ( object.isLine ) { - - var lineWidth = material.linewidth; - - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material + return this._hand; - state.setLineWidth( lineWidth * getTargetPixelRatio() ); + }, - if ( object.isLineSegments ) { + getTargetRaySpace: function () { - renderer.setMode( 1 ); + if ( this._targetRay === null ) { - } else if ( object.isLineLoop ) { + this._targetRay = new Group(); + this._targetRay.matrixAutoUpdate = false; + this._targetRay.visible = false; - renderer.setMode( 2 ); + } - } else { + return this._targetRay; - renderer.setMode( 3 ); + }, - } + getGripSpace: function () { - } else if ( object.isPoints ) { + if ( this._grip === null ) { - renderer.setMode( 0 ); + this._grip = new Group(); + this._grip.matrixAutoUpdate = false; + this._grip.visible = false; - } else if ( object.isSprite ) { + } - renderer.setMode( 4 ); + return this._grip; - } + }, - if ( geometry && geometry.isInstancedBufferGeometry ) { + dispatchEvent: function ( event ) { - if ( geometry.maxInstancedCount > 0 ) { + if ( this._targetRay !== null ) { - renderer.renderInstances( geometry, drawStart, drawCount ); + this._targetRay.dispatchEvent( event ); - } + } - } else { + if ( this._grip !== null ) { - renderer.render( drawStart, drawCount ); + this._grip.dispatchEvent( event ); } - }; - - function setupVertexAttributes( material, program, geometry ) { + if ( this._hand !== null ) { - if ( geometry && geometry.isInstancedBufferGeometry & ! capabilities.isWebGL2 ) { + this._hand.dispatchEvent( event ); - if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) { + } - console.error( 'THREE.WebGLRenderer.setupVertexAttributes: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + return this; - } + }, - } + disconnect: function ( inputSource ) { - state.initAttributes(); + this.dispatchEvent( { type: 'disconnected', data: inputSource } ); - var geometryAttributes = geometry.attributes; + if ( this._targetRay !== null ) { - var programAttributes = program.getAttributes(); + this._targetRay.visible = false; - var materialDefaultAttributeValues = material.defaultAttributeValues; + } - for ( var name in programAttributes ) { + if ( this._grip !== null ) { - var programAttribute = programAttributes[ name ]; + this._grip.visible = false; - if ( programAttribute >= 0 ) { + } - var geometryAttribute = geometryAttributes[ name ]; + if ( this._hand !== null ) { - if ( geometryAttribute !== undefined ) { + this._hand.visible = false; - var normalized = geometryAttribute.normalized; - var size = geometryAttribute.itemSize; + } - var attribute = attributes.get( geometryAttribute ); + return this; - // TODO Attribute may not be available on context restore + }, - if ( attribute === undefined ) continue; + update: function ( inputSource, frame, referenceSpace ) { - var buffer = attribute.buffer; - var type = attribute.type; - var bytesPerElement = attribute.bytesPerElement; + var inputPose = null; + var gripPose = null; + var handPose = null; - if ( geometryAttribute.isInterleavedBufferAttribute ) { + var targetRay = this._targetRay; + var grip = this._grip; + var hand = this._hand; - var data = geometryAttribute.data; - var stride = data.stride; - var offset = geometryAttribute.offset; + if ( inputSource ) { - if ( data && data.isInstancedInterleavedBuffer ) { + if ( inputSource.hand ) { - state.enableAttributeAndDivisor( programAttribute, data.meshPerAttribute ); + handPose = true; - if ( geometry.maxInstancedCount === undefined ) { + for ( var i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i ++ ) { - geometry.maxInstancedCount = data.meshPerAttribute * data.count; + if ( inputSource.hand[ i ] ) { - } + // Update the joints groups with the XRJoint poses + var jointPose = frame.getJointPose( inputSource.hand[ i ], referenceSpace ); + var joint = hand.joints[ i ]; - } else { + if ( jointPose !== null ) { - state.enableAttribute( programAttribute ); + joint.matrix.fromArray( jointPose.transform.matrix ); + joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); + joint.jointRadius = jointPose.radius; } - _gl.bindBuffer( 34962, buffer ); - _gl.vertexAttribPointer( programAttribute, size, type, normalized, stride * bytesPerElement, offset * bytesPerElement ); - - } else { + joint.visible = jointPose !== null; - if ( geometryAttribute.isInstancedBufferAttribute ) { + // Custom events - state.enableAttributeAndDivisor( programAttribute, geometryAttribute.meshPerAttribute ); + // Check pinch + var indexTip = hand.joints[ window.XRHand.INDEX_PHALANX_TIP ]; + var thumbTip = hand.joints[ window.XRHand.THUMB_PHALANX_TIP ]; + var distance = indexTip.position.distanceTo( thumbTip.position ); - if ( geometry.maxInstancedCount === undefined ) { + var distanceToPinch = 0.02; + var threshold = 0.005; - geometry.maxInstancedCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; + if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) { - } + hand.inputState.pinching = false; + this.dispatchEvent( { + type: "pinchend", + handedness: inputSource.handedness, + target: this + } ); - } else { + } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) { - state.enableAttribute( programAttribute ); + hand.inputState.pinching = true; + this.dispatchEvent( { + type: "pinchstart", + handedness: inputSource.handedness, + target: this + } ); } - _gl.bindBuffer( 34962, buffer ); - _gl.vertexAttribPointer( programAttribute, size, type, normalized, 0, 0 ); - } - } else if ( materialDefaultAttributeValues !== undefined ) { + } - var value = materialDefaultAttributeValues[ name ]; + } else { - if ( value !== undefined ) { + if ( targetRay !== null ) { - switch ( value.length ) { + inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace ); - case 2: - _gl.vertexAttrib2fv( programAttribute, value ); - break; + if ( inputPose !== null ) { - case 3: - _gl.vertexAttrib3fv( programAttribute, value ); - break; + targetRay.matrix.fromArray( inputPose.transform.matrix ); + targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); - case 4: - _gl.vertexAttrib4fv( programAttribute, value ); - break; + } - default: - _gl.vertexAttrib1fv( programAttribute, value ); + } - } + 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 ); } @@ -22932,972 +23344,858 @@ } - state.disableUnusedAttributes(); + if ( targetRay !== null ) { - } + targetRay.visible = ( inputPose !== null ); - // Compile + } - this.compile = function ( scene, camera ) { + if ( grip !== null ) { - currentRenderState = renderStates.get( scene, camera ); - currentRenderState.init(); + grip.visible = ( gripPose !== null ); - scene.traverse( function ( object ) { + } - if ( object.isLight ) { + if ( hand !== null ) { - currentRenderState.pushLight( object ); + hand.visible = ( handPose !== null ); - if ( object.castShadow ) { + } - currentRenderState.pushShadow( object ); + return this; - } + } - } - - } ); - - currentRenderState.setupLights( camera ); + } ); - scene.traverse( function ( object ) { + function WebXRManager( renderer, gl ) { - if ( object.material ) { + var scope = this; - if ( Array.isArray( object.material ) ) { + var session = null; - for ( var i = 0; i < object.material.length; i ++ ) { + var framebufferScaleFactor = 1.0; - initMaterial( object.material[ i ], scene.fog, object ); + var referenceSpace = null; + var referenceSpaceType = 'local-floor'; - } + var pose = null; - } else { + var controllers = []; + var inputSourcesMap = new Map(); - initMaterial( object.material, scene.fog, object ); + // - } + var cameraL = new PerspectiveCamera(); + cameraL.layers.enable( 1 ); + cameraL.viewport = new Vector4(); - } + var cameraR = new PerspectiveCamera(); + cameraR.layers.enable( 2 ); + cameraR.viewport = new Vector4(); - } ); + var cameras = [ cameraL, cameraR ]; - }; + var cameraVR = new ArrayCamera(); + cameraVR.layers.enable( 1 ); + cameraVR.layers.enable( 2 ); - // Animation Loop + var _currentDepthNear = null; + var _currentDepthFar = null; - var onAnimationFrameCallback = null; + // - function onAnimationFrame( time ) { + this.enabled = false; - if ( vr.isPresenting() ) return; - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); + this.isPresenting = false; - } + this.getController = function ( index ) { - var animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); + var controller = controllers[ index ]; - if ( typeof window !== 'undefined' ) animation.setContext( window ); + if ( controller === undefined ) { - this.setAnimationLoop = function ( callback ) { + controller = new WebXRController(); + controllers[ index ] = controller; - onAnimationFrameCallback = callback; - vr.setAnimationLoop( callback ); + } - animation.start(); + return controller.getTargetRaySpace(); }; - // Rendering + this.getControllerGrip = function ( index ) { - this.render = function ( scene, camera, renderTarget, forceClear ) { + var controller = controllers[ index ]; - if ( ! ( camera && camera.isCamera ) ) { + if ( controller === undefined ) { - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + controller = new WebXRController(); + controllers[ index ] = controller; } - if ( _isContextLost ) return; - - // reset caching for this frame - - _currentGeometryProgram.geometry = null; - _currentGeometryProgram.program = null; - _currentGeometryProgram.wireframe = false; - _currentMaterialId = - 1; - _currentCamera = null; - - // update scene graph + return controller.getGripSpace(); - if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + }; - // update camera matrices and frustum + this.getHand = function ( index ) { - if ( camera.parent === null ) camera.updateMatrixWorld(); + var controller = controllers[ index ]; - if ( vr.enabled ) { + if ( controller === undefined ) { - camera = vr.getCamera( camera ); + controller = new WebXRController(); + controllers[ index ] = controller; } - // - - currentRenderState = renderStates.get( scene, camera ); - currentRenderState.init(); - - scene.onBeforeRender( _this, scene, camera, renderTarget ); + return controller.getHandSpace(); - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromMatrix( _projScreenMatrix ); + }; - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); + // - currentRenderList = renderLists.get( scene, camera ); - currentRenderList.init(); + function onSessionEvent( event ) { - projectObject( scene, camera, _this.sortObjects ); + var controller = inputSourcesMap.get( event.inputSource ); - if ( _this.sortObjects === true ) { + if ( controller ) { - currentRenderList.sort(); + controller.dispatchEvent( { type: event.type } ); } - // + } - if ( _clippingEnabled ) _clipping.beginShadows(); + function onSessionEnd() { - var shadowsArray = currentRenderState.state.shadowsArray; + inputSourcesMap.forEach( function ( controller, inputSource ) { - shadowMap.render( shadowsArray, scene, camera ); + controller.disconnect( inputSource ); - currentRenderState.setupLights( camera ); + } ); - if ( _clippingEnabled ) _clipping.endShadows(); + inputSourcesMap.clear(); // - if ( this.info.autoReset ) this.info.reset(); - - if ( renderTarget === undefined ) { - - renderTarget = null; - - } + renderer.setFramebuffer( null ); + renderer.setRenderTarget( renderer.getRenderTarget() ); // Hack #15830 + animation.stop(); - this.setRenderTarget( renderTarget ); + scope.isPresenting = false; - // + scope.dispatchEvent( { type: 'sessionend' } ); - background.render( currentRenderList, scene, camera, forceClear ); + } - // render scene + function onRequestReferenceSpace( value ) { - var opaqueObjects = currentRenderList.opaque; - var transparentObjects = currentRenderList.transparent; + referenceSpace = value; - if ( scene.overrideMaterial ) { + animation.setContext( session ); + animation.start(); - var overrideMaterial = scene.overrideMaterial; + scope.isPresenting = true; - if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera, overrideMaterial ); - if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial ); + scope.dispatchEvent( { type: 'sessionstart' } ); - } else { + } - // opaque pass (front-to-back order) + this.setFramebufferScaleFactor = function ( value ) { - if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera ); + framebufferScaleFactor = value; - // transparent pass (back-to-front order) + if ( scope.isPresenting === true ) { - if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera ); + console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' ); } - // Generate mipmap if we're using any kind of mipmap filtering - - if ( renderTarget ) { + }; - textures.updateRenderTargetMipmap( renderTarget ); + this.setReferenceSpaceType = function ( value ) { - } + referenceSpaceType = value; - // Ensure depth buffer writing is enabled so it can be cleared on next render + if ( scope.isPresenting === true ) { - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); + console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' ); - state.setPolygonOffset( false ); + } - scene.onAfterRender( _this, scene, camera ); + }; - if ( vr.enabled ) { + this.getReferenceSpace = function () { - vr.submitFrame(); + return referenceSpace; - } + }; - // _gl.finish(); + this.getSession = function () { - currentRenderList = null; - currentRenderState = null; + return session; }; - function projectObject( object, camera, sortObjects ) { + this.setSession = function ( value ) { - if ( object.visible === false ) return; + session = value; - var visible = object.layers.test( camera.layers ); + if ( session !== null ) { - if ( visible ) { + 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 ); - if ( object.isLight ) { + var attributes = gl.getContextAttributes(); - currentRenderState.pushLight( object ); + if ( attributes.xrCompatible !== true ) { - if ( object.castShadow ) { + gl.makeXRCompatible(); - currentRenderState.pushShadow( object ); + } - } + var layerInit = { + antialias: attributes.antialias, + alpha: attributes.alpha, + depth: attributes.depth, + stencil: attributes.stencil, + framebufferScaleFactor: framebufferScaleFactor + }; - } else if ( object.isSprite ) { + // eslint-disable-next-line no-undef + var baseLayer = new XRWebGLLayer( session, gl, layerInit ); - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { + session.updateRenderState( { baseLayer: baseLayer } ); - if ( sortObjects ) { + session.requestReferenceSpace( referenceSpaceType ).then( onRequestReferenceSpace ); - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + // - } + session.addEventListener( 'inputsourceschange', updateInputSources ); - var geometry = objects.update( object ); - var material = object.material; + } - currentRenderList.push( object, geometry, material, _vector3.z, null ); + }; - } + function updateInputSources( event ) { - } else if ( object.isImmediateRenderObject ) { + var inputSources = session.inputSources; - if ( sortObjects ) { + // Assign inputSources to available controllers - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + for ( var i = 0; i < controllers.length; i ++ ) { - } + inputSourcesMap.set( inputSources[ i ], controllers[ i ] ); - currentRenderList.push( object, null, object.material, _vector3.z, null ); + } - } else if ( object.isMesh || object.isLine || object.isPoints ) { + // Notify disconnected - if ( object.isSkinnedMesh ) { + for ( var i$1 = 0; i$1 < event.removed.length; i$1 ++ ) { - object.skeleton.update(); + var inputSource = event.removed[ i$1 ]; + var controller = inputSourcesMap.get( inputSource ); - } + if ( controller ) { - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { + controller.dispatchEvent( { type: 'disconnected', data: inputSource } ); + inputSourcesMap.delete( inputSource ); - if ( sortObjects ) { + } - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + } - } + // Notify connected - var geometry = objects.update( object ); - var material = object.material; + for ( var i$2 = 0; i$2 < event.added.length; i$2 ++ ) { - if ( Array.isArray( material ) ) { + var inputSource$1 = event.added[ i$2 ]; + var controller$1 = inputSourcesMap.get( inputSource$1 ); - var groups = geometry.groups; + if ( controller$1 ) { - for ( var i = 0, l = groups.length; i < l; i ++ ) { + controller$1.dispatchEvent( { type: 'connected', data: inputSource$1 } ); - var group = groups[ i ]; - var groupMaterial = material[ group.materialIndex ]; + } - if ( groupMaterial && groupMaterial.visible ) { + } - currentRenderList.push( object, geometry, groupMaterial, _vector3.z, group ); + } - } + // - } + var cameraLPos = new Vector3(); + var cameraRPos = new Vector3(); - } else if ( material.visible ) { + /** + * 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 ); + + var ipd = cameraLPos.distanceTo( cameraRPos ); + + var projL = cameraL.projectionMatrix.elements; + var 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. + var near = projL[ 14 ] / ( projL[ 10 ] - 1 ); + var far = projL[ 14 ] / ( projL[ 10 ] + 1 ); + var topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; + var bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; + + var leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; + var rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; + var left = near * leftFov; + var right = near * rightFov; + + // Calculate the new camera's position offset from the + // left camera. xOffset should be roughly half `ipd`. + var zOffset = ipd / ( - leftFov + rightFov ); + var 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.getInverse( camera.matrixWorld ); - currentRenderList.push( object, geometry, material, _vector3.z, null ); + // 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. + var near2 = near + zOffset; + var far2 = far + zOffset; + var left2 = left - xOffset; + var right2 = right + ( ipd - xOffset ); + var top2 = topFov * far / far2 * near2; + var bottom2 = bottomFov * far / far2 * near2; - } + camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); - } + } - } + function updateCamera( camera, parent ) { - } + if ( parent === null ) { - var children = object.children; + camera.matrixWorld.copy( camera.matrix ); - for ( var i = 0, l = children.length; i < l; i ++ ) { + } else { - projectObject( children[ i ], camera, sortObjects ); + camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); } - } + camera.matrixWorldInverse.getInverse( camera.matrixWorld ); - function renderObjects( renderList, scene, camera, overrideMaterial ) { + } - for ( var i = 0, l = renderList.length; i < l; i ++ ) { + this.getCamera = function ( camera ) { - var renderItem = renderList[ i ]; + cameraVR.near = cameraR.near = cameraL.near = camera.near; + cameraVR.far = cameraR.far = cameraL.far = camera.far; - var object = renderItem.object; - var geometry = renderItem.geometry; - var material = overrideMaterial === undefined ? renderItem.material : overrideMaterial; - var group = renderItem.group; + if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) { - if ( camera.isArrayCamera ) { + // Note that the new renderState won't apply until the next frame. See #18320 - _currentArrayCamera = camera; + session.updateRenderState( { + depthNear: cameraVR.near, + depthFar: cameraVR.far + } ); - var cameras = camera.cameras; + _currentDepthNear = cameraVR.near; + _currentDepthFar = cameraVR.far; - for ( var j = 0, jl = cameras.length; j < jl; j ++ ) { + } - var camera2 = cameras[ j ]; + var parent = camera.parent; + var cameras = cameraVR.cameras; - if ( object.layers.test( camera2.layers ) ) { + updateCamera( cameraVR, parent ); - if ( 'viewport' in camera2 ) { // XR + for ( var i = 0; i < cameras.length; i ++ ) { - state.viewport( _currentViewport.copy( camera2.viewport ) ); + updateCamera( cameras[ i ], parent ); - } else { + } - var bounds = camera2.bounds; + // update camera and its children - var x = bounds.x * _width; - var y = bounds.y * _height; - var width = bounds.z * _width; - var height = bounds.w * _height; + camera.matrixWorld.copy( cameraVR.matrixWorld ); - state.viewport( _currentViewport.set( x, y, width, height ).multiplyScalar( _pixelRatio ) ); + var children = camera.children; - } + for ( var i$1 = 0, l = children.length; i$1 < l; i$1 ++ ) { - currentRenderState.setupLights( camera2 ); + children[ i$1 ].updateMatrixWorld( true ); - renderObject( object, scene, camera2, geometry, material, group ); + } - } + // update projection matrix for proper view frustum culling - } + if ( cameras.length === 2 ) { - } else { + setProjectionFromUnion( cameraVR, cameraL, cameraR ); - _currentArrayCamera = null; + } else { - renderObject( object, scene, camera, geometry, material, group ); + // assume single camera setup (AR) - } + cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); } - } - - function renderObject( object, scene, camera, geometry, material, group ) { + return cameraVR; - object.onBeforeRender( _this, scene, camera, geometry, material, group ); - currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); + }; - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + // Animation Loop - if ( object.isImmediateRenderObject ) { + var onAnimationFrameCallback = null; - state.setMaterial( material ); + function onAnimationFrame( time, frame ) { - var program = setProgram( camera, scene.fog, material, object ); + pose = frame.getViewerPose( referenceSpace ); - _currentGeometryProgram.geometry = null; - _currentGeometryProgram.program = null; - _currentGeometryProgram.wireframe = false; + if ( pose !== null ) { - renderObjectImmediate( object, program ); + var views = pose.views; + var baseLayer = session.renderState.baseLayer; - } else { + renderer.setFramebuffer( baseLayer.framebuffer ); - _this.renderBufferDirect( camera, scene.fog, geometry, material, object, group ); + var cameraVRNeedsUpdate = false; - } + // check if it's necessary to rebuild cameraVR's camera list - object.onAfterRender( _this, scene, camera, geometry, material, group ); - currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); + if ( views.length !== cameraVR.cameras.length ) { - } + cameraVR.cameras.length = 0; + cameraVRNeedsUpdate = true; - function initMaterial( material, fog, object ) { + } - var materialProperties = properties.get( material ); + for ( var i = 0; i < views.length; i ++ ) { - var lights = currentRenderState.state.lights; - var shadowsArray = currentRenderState.state.shadowsArray; + var view = views[ i ]; + var viewport = baseLayer.getViewport( view ); - var lightsHash = materialProperties.lightsHash; - var lightsStateHash = lights.state.hash; + var 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 ); - var parameters = programCache.getParameters( - material, lights.state, shadowsArray, fog, _clipping.numPlanes, _clipping.numIntersection, object ); + if ( i === 0 ) { - var code = programCache.getProgramCode( material, parameters ); + cameraVR.matrix.copy( camera.matrix ); - var program = materialProperties.program; - var programChange = true; + } - if ( program === undefined ) { + if ( cameraVRNeedsUpdate === true ) { - // new material - material.addEventListener( 'dispose', onMaterialDispose ); + cameraVR.cameras.push( camera ); - } else if ( program.code !== code ) { + } - // changed glsl or parameters - releaseMaterialProgramReference( material ); + } - } else if ( lightsHash.stateID !== lightsStateHash.stateID || - lightsHash.directionalLength !== lightsStateHash.directionalLength || - lightsHash.pointLength !== lightsStateHash.pointLength || - lightsHash.spotLength !== lightsStateHash.spotLength || - lightsHash.rectAreaLength !== lightsStateHash.rectAreaLength || - lightsHash.hemiLength !== lightsStateHash.hemiLength || - lightsHash.shadowsLength !== lightsStateHash.shadowsLength ) { - - lightsHash.stateID = lightsStateHash.stateID; - lightsHash.directionalLength = lightsStateHash.directionalLength; - lightsHash.pointLength = lightsStateHash.pointLength; - lightsHash.spotLength = lightsStateHash.spotLength; - lightsHash.rectAreaLength = lightsStateHash.rectAreaLength; - lightsHash.hemiLength = lightsStateHash.hemiLength; - lightsHash.shadowsLength = lightsStateHash.shadowsLength; + } - programChange = false; + // - } else if ( parameters.shaderID !== undefined ) { + var inputSources = session.inputSources; - // same glsl and uniform list - return; + for ( var i$1 = 0; i$1 < controllers.length; i$1 ++ ) { - } else { + var controller = controllers[ i$1 ]; + var inputSource = inputSources[ i$1 ]; - // only rebuild uniform list - programChange = false; + controller.update( inputSource, frame, referenceSpace ); } - if ( programChange ) { + if ( onAnimationFrameCallback ) { onAnimationFrameCallback( time, frame ); } - if ( parameters.shaderID ) { + } - var shader = ShaderLib[ parameters.shaderID ]; + var animation = new WebGLAnimation(); + animation.setAnimationLoop( onAnimationFrame ); - materialProperties.shader = { - name: material.type, - uniforms: UniformsUtils.clone( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader - }; + this.setAnimationLoop = function ( callback ) { - } else { + onAnimationFrameCallback = callback; - materialProperties.shader = { - name: material.type, - uniforms: material.uniforms, - vertexShader: material.vertexShader, - fragmentShader: material.fragmentShader - }; + }; - } + this.dispose = function () {}; - material.onBeforeCompile( materialProperties.shader, _this ); + } - // Computing code again as onBeforeCompile may have changed the shaders - code = programCache.getProgramCode( material, parameters ); + Object.assign( WebXRManager.prototype, EventDispatcher.prototype ); - program = programCache.acquireProgram( material, materialProperties.shader, parameters, code ); + function WebGLMaterials( properties ) { - materialProperties.program = program; - material.program = program; + function refreshFogUniforms( uniforms, fog ) { - } + uniforms.fogColor.value.copy( fog.color ); - var programAttributes = program.getAttributes(); + if ( fog.isFog ) { - if ( material.morphTargets ) { + uniforms.fogNear.value = fog.near; + uniforms.fogFar.value = fog.far; - material.numSupportedMorphTargets = 0; + } else if ( fog.isFogExp2 ) { - for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { + uniforms.fogDensity.value = fog.density; - if ( programAttributes[ 'morphTarget' + i ] >= 0 ) { + } - material.numSupportedMorphTargets ++; + } - } + function refreshMaterialUniforms( uniforms, material, environment, pixelRatio, height ) { - } + if ( material.isMeshBasicMaterial ) { - } + refreshUniformsCommon( uniforms, material ); - if ( material.morphNormals ) { + } else if ( material.isMeshLambertMaterial ) { - material.numSupportedMorphNormals = 0; + refreshUniformsCommon( uniforms, material ); + refreshUniformsLambert( uniforms, material ); - for ( var i = 0; i < _this.maxMorphNormals; i ++ ) { + } else if ( material.isMeshToonMaterial ) { - if ( programAttributes[ 'morphNormal' + i ] >= 0 ) { + refreshUniformsCommon( uniforms, material ); + refreshUniformsToon( uniforms, material ); - material.numSupportedMorphNormals ++; + } else if ( material.isMeshPhongMaterial ) { - } + refreshUniformsCommon( uniforms, material ); + refreshUniformsPhong( uniforms, material ); - } + } else if ( material.isMeshStandardMaterial ) { - } + refreshUniformsCommon( uniforms, material, environment ); - var uniforms = materialProperties.shader.uniforms; + if ( material.isMeshPhysicalMaterial ) { - if ( ! material.isShaderMaterial && - ! material.isRawShaderMaterial || - material.clipping === true ) { + refreshUniformsPhysical( uniforms, material, environment ); - materialProperties.numClippingPlanes = _clipping.numPlanes; - materialProperties.numIntersection = _clipping.numIntersection; - uniforms.clippingPlanes = _clipping.uniform; + } else { - } + refreshUniformsStandard( uniforms, material, environment ); - materialProperties.fog = fog; + } - // store the light setup it was created for - if ( lightsHash === undefined ) { + } else if ( material.isMeshMatcapMaterial ) { - materialProperties.lightsHash = lightsHash = {}; + refreshUniformsCommon( uniforms, material ); + refreshUniformsMatcap( uniforms, material ); - } + } else if ( material.isMeshDepthMaterial ) { - lightsHash.stateID = lightsStateHash.stateID; - lightsHash.directionalLength = lightsStateHash.directionalLength; - lightsHash.pointLength = lightsStateHash.pointLength; - lightsHash.spotLength = lightsStateHash.spotLength; - lightsHash.rectAreaLength = lightsStateHash.rectAreaLength; - lightsHash.hemiLength = lightsStateHash.hemiLength; - lightsHash.shadowsLength = lightsStateHash.shadowsLength; + refreshUniformsCommon( uniforms, material ); + refreshUniformsDepth( uniforms, material ); - if ( material.lights ) { + } else if ( material.isMeshDistanceMaterial ) { - // wire up the material to this renderer's lighting state + refreshUniformsCommon( uniforms, material ); + refreshUniformsDistance( uniforms, material ); - uniforms.ambientLightColor.value = lights.state.ambient; - uniforms.directionalLights.value = lights.state.directional; - uniforms.spotLights.value = lights.state.spot; - uniforms.rectAreaLights.value = lights.state.rectArea; - uniforms.pointLights.value = lights.state.point; - uniforms.hemisphereLights.value = lights.state.hemi; + } else if ( material.isMeshNormalMaterial ) { - 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 + refreshUniformsCommon( uniforms, material ); + refreshUniformsNormal( uniforms, material ); - } + } else if ( material.isLineBasicMaterial ) { - var progUniforms = materialProperties.program.getUniforms(), - uniformsList = - WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); + refreshUniformsLine( uniforms, material ); - materialProperties.uniformsList = uniformsList; + if ( material.isLineDashedMaterial ) { - } + refreshUniformsDash( uniforms, material ); - function setProgram( camera, fog, material, object ) { + } - _usedTextureUnits = 0; + } else if ( material.isPointsMaterial ) { - var materialProperties = properties.get( material ); - var lights = currentRenderState.state.lights; + refreshUniformsPoints( uniforms, material, pixelRatio, height ); - var lightsHash = materialProperties.lightsHash; - var lightsStateHash = lights.state.hash; + } else if ( material.isSpriteMaterial ) { - if ( _clippingEnabled ) { + refreshUniformsSprites( uniforms, material ); - if ( _localClippingEnabled || camera !== _currentCamera ) { + } else if ( material.isShadowMaterial ) { - var useCache = - camera === _currentCamera && - material.id === _currentMaterialId; + uniforms.color.value.copy( material.color ); + uniforms.opacity.value = material.opacity; - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - _clipping.setState( - material.clippingPlanes, material.clipIntersection, material.clipShadows, - camera, materialProperties, useCache ); + } else if ( material.isShaderMaterial ) { - } + material.uniformsNeedUpdate = false; // #15581 } - if ( material.needsUpdate === false ) { - - if ( materialProperties.program === undefined ) { - - material.needsUpdate = true; + } - } else if ( material.fog && materialProperties.fog !== fog ) { + function refreshUniformsCommon( uniforms, material, environment ) { - material.needsUpdate = true; + uniforms.opacity.value = material.opacity; - } else if ( material.lights && ( lightsHash.stateID !== lightsStateHash.stateID || - lightsHash.directionalLength !== lightsStateHash.directionalLength || - lightsHash.pointLength !== lightsStateHash.pointLength || - lightsHash.spotLength !== lightsStateHash.spotLength || - lightsHash.rectAreaLength !== lightsStateHash.rectAreaLength || - lightsHash.hemiLength !== lightsStateHash.hemiLength || - lightsHash.shadowsLength !== lightsStateHash.shadowsLength ) ) { + if ( material.color ) { - material.needsUpdate = true; + uniforms.diffuse.value.copy( material.color ); - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== _clipping.numPlanes || - materialProperties.numIntersection !== _clipping.numIntersection ) ) { + } - material.needsUpdate = true; + if ( material.emissive ) { - } + uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); } - if ( material.needsUpdate ) { + if ( material.map ) { - initMaterial( material, fog, object ); - material.needsUpdate = false; + uniforms.map.value = material.map; } - var refreshProgram = false; - var refreshMaterial = false; - var refreshLights = false; + if ( material.alphaMap ) { - var program = materialProperties.program, - p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.shader.uniforms; + uniforms.alphaMap.value = material.alphaMap; - if ( state.useProgram( program.program ) ) { + } - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; + if ( material.specularMap ) { + + uniforms.specularMap.value = material.specularMap; } - if ( material.id !== _currentMaterialId ) { + var envMap = material.envMap || environment; - _currentMaterialId = material.id; + if ( envMap ) { - refreshMaterial = true; + uniforms.envMap.value = envMap; - } + uniforms.flipEnvMap.value = envMap.isCubeTexture ? - 1 : 1; - if ( refreshProgram || _currentCamera !== camera ) { + uniforms.reflectivity.value = material.reflectivity; + uniforms.refractionRatio.value = material.refractionRatio; - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + var maxMipLevel = properties.get( envMap ).__maxMipLevel; - if ( capabilities.logarithmicDepthBuffer ) { + if ( maxMipLevel !== undefined ) { - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); + uniforms.maxMipLevel.value = maxMipLevel; } - 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: + if ( material.lightMap ) { - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done + uniforms.lightMap.value = material.lightMap; + uniforms.lightMapIntensity.value = material.lightMapIntensity; - } + } - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + if ( material.aoMap ) { - if ( material.isShaderMaterial || - material.isMeshPhongMaterial || - material.isMeshStandardMaterial || - material.envMap ) { + uniforms.aoMap.value = material.aoMap; + uniforms.aoMapIntensity.value = material.aoMapIntensity; - var uCamPos = p_uniforms.map.cameraPosition; + } - if ( uCamPos !== undefined ) { + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + // 5. alpha map + // 6. emissive map - uCamPos.setValue( _gl, - _vector3.setFromMatrixPosition( camera.matrixWorld ) ); + var uvScaleMap; - } + if ( material.map ) { - } + uvScaleMap = material.map; - if ( material.isMeshPhongMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial || - material.skinning ) { + } else if ( material.specularMap ) { - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); + uvScaleMap = material.specularMap; - } + } else if ( material.displacementMap ) { - } + uvScaleMap = material.displacementMap; - // skinning uniforms must be set even if material didn't change - // auto-setting of texture unit for bone texture must go before other textures - // not sure why, but otherwise weird things happen + } else if ( material.normalMap ) { - if ( material.skinning ) { + uvScaleMap = material.normalMap; - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); + } else if ( material.bumpMap ) { - var skeleton = object.skeleton; + uvScaleMap = material.bumpMap; - if ( skeleton ) { + } else if ( material.roughnessMap ) { - var bones = skeleton.bones; + uvScaleMap = material.roughnessMap; - if ( capabilities.floatVertexTextures ) { + } else if ( material.metalnessMap ) { - if ( skeleton.boneTexture === undefined ) { + uvScaleMap = material.metalnessMap; - // 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) + } else if ( material.alphaMap ) { + uvScaleMap = material.alphaMap; - var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix - size = _Math.ceilPowerOfTwo( size ); - size = Math.max( size, 4 ); + } else if ( material.emissiveMap ) { - var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel - boneMatrices.set( skeleton.boneMatrices ); // copy current values + uvScaleMap = material.emissiveMap; - var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); - boneTexture.needsUpdate = true; + } - skeleton.boneMatrices = boneMatrices; - skeleton.boneTexture = boneTexture; - skeleton.boneTextureSize = size; + if ( uvScaleMap !== undefined ) { - } + // backwards compatibility + if ( uvScaleMap.isWebGLRenderTarget ) { - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture ); - p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); + uvScaleMap = uvScaleMap.texture; - } else { + } - p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); + if ( uvScaleMap.matrixAutoUpdate === true ) { - } + uvScaleMap.updateMatrix(); } + uniforms.uvTransform.value.copy( uvScaleMap.matrix ); + } - if ( refreshMaterial ) { + // uv repeat and offset setting priorities for uv2 + // 1. ao map + // 2. light map - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - p_uniforms.setValue( _gl, 'toneMappingWhitePoint', _this.toneMappingWhitePoint ); + var uv2ScaleMap; - if ( material.lights ) { + if ( material.aoMap ) { - // the current material requires lighting info + uv2ScaleMap = material.aoMap; - // 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 + } else if ( material.lightMap ) { - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); + uv2ScaleMap = material.lightMap; - } + } - // refresh uniforms common to several materials + if ( uv2ScaleMap !== undefined ) { - if ( fog && material.fog ) { + // backwards compatibility + if ( uv2ScaleMap.isWebGLRenderTarget ) { - refreshUniformsFog( m_uniforms, fog ); + uv2ScaleMap = uv2ScaleMap.texture; } - if ( material.isMeshBasicMaterial ) { + if ( uv2ScaleMap.matrixAutoUpdate === true ) { - refreshUniformsCommon( m_uniforms, material ); + uv2ScaleMap.updateMatrix(); - } else if ( material.isMeshLambertMaterial ) { + } - refreshUniformsCommon( m_uniforms, material ); - refreshUniformsLambert( m_uniforms, material ); + uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix ); - } else if ( material.isMeshPhongMaterial ) { + } - refreshUniformsCommon( m_uniforms, material ); + } - if ( material.isMeshToonMaterial ) { + function refreshUniformsLine( uniforms, material ) { - refreshUniformsToon( m_uniforms, material ); + uniforms.diffuse.value.copy( material.color ); + uniforms.opacity.value = material.opacity; - } else { + } - refreshUniformsPhong( m_uniforms, material ); + function refreshUniformsDash( uniforms, material ) { - } - - } else if ( material.isMeshStandardMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); - - if ( material.isMeshPhysicalMaterial ) { - - refreshUniformsPhysical( m_uniforms, material ); - - } else { - - refreshUniformsStandard( m_uniforms, material ); - - } - - } else if ( material.isMeshMatcapMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); - - refreshUniformsMatcap( m_uniforms, material ); - - } else if ( material.isMeshDepthMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); - refreshUniformsDepth( m_uniforms, material ); - - } else if ( material.isMeshDistanceMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); - refreshUniformsDistance( m_uniforms, material ); - - } else if ( material.isMeshNormalMaterial ) { - - refreshUniformsCommon( m_uniforms, material ); - refreshUniformsNormal( m_uniforms, material ); + uniforms.dashSize.value = material.dashSize; + uniforms.totalSize.value = material.dashSize + material.gapSize; + uniforms.scale.value = material.scale; - } else if ( material.isLineBasicMaterial ) { + } - refreshUniformsLine( m_uniforms, material ); + function refreshUniformsPoints( uniforms, material, pixelRatio, height ) { - if ( material.isLineDashedMaterial ) { + uniforms.diffuse.value.copy( material.color ); + uniforms.opacity.value = material.opacity; + uniforms.size.value = material.size * pixelRatio; + uniforms.scale.value = height * 0.5; - refreshUniformsDash( m_uniforms, material ); + if ( material.map ) { - } + uniforms.map.value = material.map; - } else if ( material.isPointsMaterial ) { + } - refreshUniformsPoints( m_uniforms, material ); + if ( material.alphaMap ) { - } else if ( material.isSpriteMaterial ) { + uniforms.alphaMap.value = material.alphaMap; - refreshUniformsSprites( m_uniforms, material ); + } - } else if ( material.isShadowMaterial ) { + // uv repeat and offset setting priorities + // 1. color map + // 2. alpha map - m_uniforms.color.value = material.color; - m_uniforms.opacity.value = material.opacity; + var uvScaleMap; - } + if ( material.map ) { - // RectAreaLight Texture - // TODO (mrdoob): Find a nicer implementation + uvScaleMap = material.map; - if ( m_uniforms.ltc_1 !== undefined ) m_uniforms.ltc_1.value = UniformsLib.LTC_1; - if ( m_uniforms.ltc_2 !== undefined ) m_uniforms.ltc_2.value = UniformsLib.LTC_2; + } else if ( material.alphaMap ) { - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this ); + uvScaleMap = material.alphaMap; } - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { + if ( uvScaleMap !== undefined ) { - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, _this ); - material.uniformsNeedUpdate = false; + if ( uvScaleMap.matrixAutoUpdate === true ) { - } + uvScaleMap.updateMatrix(); - if ( material.isSpriteMaterial ) { + } - p_uniforms.setValue( _gl, 'center', object.center ); + uniforms.uvTransform.value.copy( uvScaleMap.matrix ); } - // 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; - } - // Uniforms (refresh uniforms objects) - - function refreshUniformsCommon( uniforms, material ) { + function refreshUniformsSprites( uniforms, material ) { + uniforms.diffuse.value.copy( material.color ); uniforms.opacity.value = material.opacity; - - if ( material.color ) { - - uniforms.diffuse.value = material.color; - - } - - if ( material.emissive ) { - - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - - } + uniforms.rotation.value = material.rotation; if ( material.map ) { @@ -23911,50 +24209,9 @@ } - if ( material.specularMap ) { - - uniforms.specularMap.value = material.specularMap; - - } - - if ( material.envMap ) { - - uniforms.envMap.value = material.envMap; - - // don't flip CubeTexture envMaps, flip everything else: - // WebGLRenderTargetCube will be flipped for backwards compatibility - // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture - // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future - uniforms.flipEnvMap.value = ( ! ( material.envMap && material.envMap.isCubeTexture ) ) ? 1 : - 1; - - uniforms.reflectivity.value = material.reflectivity; - uniforms.refractionRatio.value = material.refractionRatio; - - uniforms.maxMipLevel.value = properties.get( material.envMap ).__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. normal map - // 4. bump map - // 5. alpha map - // 6. emissive map + // 2. alpha map var uvScaleMap; @@ -23962,49 +24219,14 @@ 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; - } if ( uvScaleMap !== undefined ) { - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - if ( uvScaleMap.matrixAutoUpdate === true ) { uvScaleMap.updateMatrix(); @@ -24017,97 +24239,61 @@ } - function refreshUniformsLine( uniforms, material ) { - - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; - - } - - function refreshUniformsDash( uniforms, material ) { - - uniforms.dashSize.value = material.dashSize; - uniforms.totalSize.value = material.dashSize + material.gapSize; - uniforms.scale.value = material.scale; - - } - - function refreshUniformsPoints( uniforms, material ) { - - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; - uniforms.size.value = material.size * _pixelRatio; - uniforms.scale.value = _height * 0.5; - - uniforms.map.value = material.map; - - if ( material.map !== null ) { - - if ( material.map.matrixAutoUpdate === true ) { - - material.map.updateMatrix(); + function refreshUniformsLambert( uniforms, material ) { - } + if ( material.emissiveMap ) { - uniforms.uvTransform.value.copy( material.map.matrix ); + uniforms.emissiveMap.value = material.emissiveMap; } } - function refreshUniformsSprites( uniforms, material ) { + function refreshUniformsPhong( uniforms, material ) { - uniforms.diffuse.value = material.color; - uniforms.opacity.value = material.opacity; - uniforms.rotation.value = material.rotation; - uniforms.map.value = material.map; + uniforms.specular.value.copy( material.specular ); + uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) - if ( material.map !== null ) { + if ( material.emissiveMap ) { - if ( material.map.matrixAutoUpdate === true ) { + uniforms.emissiveMap.value = material.emissiveMap; - material.map.updateMatrix(); + } - } + if ( material.bumpMap ) { - uniforms.uvTransform.value.copy( material.map.matrix ); + uniforms.bumpMap.value = material.bumpMap; + uniforms.bumpScale.value = material.bumpScale; + if ( material.side === BackSide ) { uniforms.bumpScale.value *= - 1; } } - } - - function refreshUniformsFog( uniforms, fog ) { - - uniforms.fogColor.value = fog.color; + if ( material.normalMap ) { - if ( fog.isFog ) { + uniforms.normalMap.value = material.normalMap; + uniforms.normalScale.value.copy( material.normalScale ); + if ( material.side === BackSide ) { uniforms.normalScale.value.negate(); } - uniforms.fogNear.value = fog.near; - uniforms.fogFar.value = fog.far; + } - } else if ( fog.isFogExp2 ) { + if ( material.displacementMap ) { - uniforms.fogDensity.value = fog.density; + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; } } - function refreshUniformsLambert( uniforms, material ) { + function refreshUniformsToon( uniforms, material ) { - if ( material.emissiveMap ) { + if ( material.gradientMap ) { - uniforms.emissiveMap.value = material.emissiveMap; + uniforms.gradientMap.value = material.gradientMap; } - } - - function refreshUniformsPhong( uniforms, material ) { - - uniforms.specular.value = 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; @@ -24118,7 +24304,7 @@ uniforms.bumpMap.value = material.bumpMap; uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; + if ( material.side === BackSide ) { uniforms.bumpScale.value *= - 1; } } @@ -24126,7 +24312,7 @@ uniforms.normalMap.value = material.normalMap; uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); + if ( material.side === BackSide ) { uniforms.normalScale.value.negate(); } } @@ -24140,19 +24326,7 @@ } - function refreshUniformsToon( uniforms, material ) { - - refreshUniformsPhong( uniforms, material ); - - if ( material.gradientMap ) { - - uniforms.gradientMap.value = material.gradientMap; - - } - - } - - function refreshUniformsStandard( uniforms, material ) { + function refreshUniformsStandard( uniforms, material, environment ) { uniforms.roughness.value = material.roughness; uniforms.metalness.value = material.metalness; @@ -24179,7 +24353,7 @@ uniforms.bumpMap.value = material.bumpMap; uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; + if ( material.side === BackSide ) { uniforms.bumpScale.value *= - 1; } } @@ -24187,7 +24361,7 @@ uniforms.normalMap.value = material.normalMap; uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); + if ( material.side === BackSide ) { uniforms.normalScale.value.negate(); } } @@ -24199,7 +24373,7 @@ } - if ( material.envMap ) { + if ( material.envMap || environment ) { //uniforms.envMap.value = material.envMap; // part of uniforms common uniforms.envMapIntensity.value = material.envMapIntensity; @@ -24208,14 +24382,48 @@ } - function refreshUniformsPhysical( uniforms, material ) { + function refreshUniformsPhysical( uniforms, material, environment ) { - refreshUniformsStandard( uniforms, material ); + refreshUniformsStandard( uniforms, material, environment ); uniforms.reflectivity.value = material.reflectivity; // also part of uniforms common - uniforms.clearCoat.value = material.clearCoat; - uniforms.clearCoatRoughness.value = material.clearCoatRoughness; + uniforms.clearcoat.value = material.clearcoat; + uniforms.clearcoatRoughness.value = material.clearcoatRoughness; + if ( material.sheen ) { uniforms.sheen.value.copy( material.sheen ); } + + 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(); + + } + + } + + uniforms.transmission.value = material.transmission; + + if ( material.transmissionMap ) { + + uniforms.transmissionMap.value = material.transmissionMap; + + } } @@ -24231,7 +24439,7 @@ uniforms.bumpMap.value = material.bumpMap; uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; + if ( material.side === BackSide ) { uniforms.bumpScale.value *= - 1; } } @@ -24239,7 +24447,7 @@ uniforms.normalMap.value = material.normalMap; uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); + if ( material.side === BackSide ) { uniforms.normalScale.value.negate(); } } @@ -24287,7 +24495,7 @@ uniforms.bumpMap.value = material.bumpMap; uniforms.bumpScale.value = material.bumpScale; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; + if ( material.side === BackSide ) { uniforms.bumpScale.value *= - 1; } } @@ -24295,7 +24503,7 @@ uniforms.normalMap.value = material.normalMap; uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); + if ( material.side === BackSide ) { uniforms.normalScale.value.negate(); } } @@ -24309,1346 +24517,1337 @@ } - // If uniforms are marked as clean, they don't need to be loaded to the GPU. + return { + refreshFogUniforms: refreshFogUniforms, + refreshMaterialUniforms: refreshMaterialUniforms + }; - function markUniformsLightsNeedsUpdate( uniforms, value ) { + } - uniforms.ambientLightColor.needsUpdate = value; + function WebGLRenderer( parameters ) { - uniforms.directionalLights.needsUpdate = value; - uniforms.pointLights.needsUpdate = value; - uniforms.spotLights.needsUpdate = value; - uniforms.rectAreaLights.needsUpdate = value; - uniforms.hemisphereLights.needsUpdate = value; + parameters = parameters || {}; - } + var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' ), + _context = parameters.context !== undefined ? parameters.context : null, - // Textures + _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; - function allocTextureUnit() { + var currentRenderList = null; + var currentRenderState = null; - var textureUnit = _usedTextureUnits; + // public properties - if ( textureUnit >= capabilities.maxTextures ) { + this.domElement = _canvas; - console.warn( 'THREE.WebGLRenderer: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); + // Debug configuration container + this.debug = { - } + /** + * Enables error checking and reporting when shader programs are being compiled + * @type {boolean} + */ + checkShaderErrors: true + }; - _usedTextureUnits += 1; + // clearing - return textureUnit; + this.autoClear = true; + this.autoClearColor = true; + this.autoClearDepth = true; + this.autoClearStencil = true; - } + // scene graph - this.allocTextureUnit = allocTextureUnit; + this.sortObjects = true; - // this.setTexture2D = setTexture2D; - this.setTexture2D = ( function () { + // user-defined clipping - var warned = false; + this.clippingPlanes = []; + this.localClippingEnabled = false; - // backwards compatibility: peel texture.texture - return function setTexture2D( texture, slot ) { + // physically based shading - if ( texture && texture.isWebGLRenderTarget ) { + this.gammaFactor = 2.0; // for backwards compatibility + this.outputEncoding = LinearEncoding; - if ( ! warned ) { + // physical lights - console.warn( "THREE.WebGLRenderer.setTexture2D: don't use render targets as textures. Use their .texture property instead." ); - warned = true; + this.physicallyCorrectLights = false; - } + // tone mapping - texture = texture.texture; + this.toneMapping = NoToneMapping; + this.toneMappingExposure = 1.0; - } + // morphs - textures.setTexture2D( texture, slot ); + this.maxMorphTargets = 8; + this.maxMorphNormals = 4; - }; + // internal properties - }() ); + var _this = this; - this.setTexture3D = ( function () { + var _isContextLost = false; - // backwards compatibility: peel texture.texture - return function setTexture3D( texture, slot ) { + // internal state cache - textures.setTexture3D( texture, slot ); + var _framebuffer = null; - }; + var _currentActiveCubeFace = 0; + var _currentActiveMipmapLevel = 0; + var _currentRenderTarget = null; + var _currentFramebuffer = null; + var _currentMaterialId = - 1; - }() ); + var _currentCamera = null; + var _currentArrayCamera = null; - this.setTexture = ( function () { + var _currentViewport = new Vector4(); + var _currentScissor = new Vector4(); + var _currentScissorTest = null; - var warned = false; + // - return function setTexture( texture, slot ) { + var _width = _canvas.width; + var _height = _canvas.height; - if ( ! warned ) { + var _pixelRatio = 1; + var _opaqueSort = null; + var _transparentSort = null; - console.warn( "THREE.WebGLRenderer: .setTexture is deprecated, use setTexture2D instead." ); - warned = true; + var _viewport = new Vector4( 0, 0, _width, _height ); + var _scissor = new Vector4( 0, 0, _width, _height ); + var _scissorTest = false; - } + // frustum - textures.setTexture2D( texture, slot ); + var _frustum = new Frustum(); - }; + // clipping - }() ); + var _clipping = new WebGLClipping(); + var _clippingEnabled = false; + var _localClippingEnabled = false; - this.setTextureCube = ( function () { + // camera matrices cache - var warned = false; + var _projScreenMatrix = new Matrix4(); - return function setTextureCube( texture, slot ) { + var _vector3 = new Vector3(); - // backwards compatibility: peel texture.texture - if ( texture && texture.isWebGLRenderTargetCube ) { + var _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; - if ( ! warned ) { + function getTargetPixelRatio() { - console.warn( "THREE.WebGLRenderer.setTextureCube: don't use cube render targets as textures. Use their .texture property instead." ); - warned = true; + return _currentRenderTarget === null ? _pixelRatio : 1; - } + } - texture = texture.texture; + // initialize - } + var _gl = _context; - // currently relying on the fact that WebGLRenderTargetCube.texture is a Texture and NOT a CubeTexture - // TODO: unify these code paths - if ( ( texture && texture.isCubeTexture ) || - ( Array.isArray( texture.image ) && texture.image.length === 6 ) ) { + function getContext( contextNames, contextAttributes ) { - // CompressedTexture can have Array in image :/ + for ( var i = 0; i < contextNames.length; i ++ ) { - // this function alone should take care of cube textures - textures.setTextureCube( texture, slot ); + var contextName = contextNames[ i ]; + var context = _canvas.getContext( contextName, contextAttributes ); + if ( context !== null ) { return context; } - } else { + } - // assumed: texture property of THREE.WebGLRenderTargetCube + return null; - textures.setTextureCubeDynamic( texture, slot ); + } - } + try { + var contextAttributes = { + alpha: _alpha, + depth: _depth, + stencil: _stencil, + antialias: _antialias, + premultipliedAlpha: _premultipliedAlpha, + preserveDrawingBuffer: _preserveDrawingBuffer, + powerPreference: _powerPreference, + failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat }; - }() ); - - // - - this.setFramebuffer = function ( value ) { - - _framebuffer = value; + // event listeners must be registered before WebGL context is created, see #12753 - }; + _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); + _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - this.getRenderTarget = function () { + if ( _gl === null ) { - return _currentRenderTarget; + var contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; - }; + if ( _this.isWebGL1Renderer === true ) { - this.setRenderTarget = function ( renderTarget ) { + contextNames.shift(); - _currentRenderTarget = renderTarget; + } - if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { + _gl = getContext( contextNames, contextAttributes ); - textures.setupRenderTarget( renderTarget ); + if ( _gl === null ) { - } + if ( getContext( contextNames ) ) { - var framebuffer = _framebuffer; - var isCube = false; + throw new Error( 'Error creating WebGL context with your selected attributes.' ); - if ( renderTarget ) { + } else { - var __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; + throw new Error( 'Error creating WebGL context.' ); - if ( renderTarget.isWebGLRenderTargetCube ) { + } - framebuffer = __webglFramebuffer[ renderTarget.activeCubeFace ]; - isCube = true; + } - } else { + } - framebuffer = __webglFramebuffer; + // Some experimental-webgl implementations do not have getShaderPrecisionFormat - } + if ( _gl.getShaderPrecisionFormat === undefined ) { - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; + _gl.getShaderPrecisionFormat = function () { - } else { + return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ); - _currentScissorTest = _scissorTest; + }; } - if ( _currentFramebuffer !== framebuffer ) { + } catch ( error ) { - _gl.bindFramebuffer( 36160, framebuffer ); - _currentFramebuffer = framebuffer; + console.error( 'THREE.WebGLRenderer: ' + error.message ); + throw error; - } + } - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); + var extensions, capabilities, state, info; + var properties, textures, attributes, geometries, objects; + var programCache, materials, renderLists, renderStates; - if ( isCube ) { + var background, morphtargets, bufferRenderer, indexedBufferRenderer; - var textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( 36160, 36064, 34069 + renderTarget.activeCubeFace, textureProperties.__webglTexture, renderTarget.activeMipMapLevel ); + var utils, bindingStates; - } + function initGLContext() { - }; + extensions = new WebGLExtensions( _gl ); - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer ) { + capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { + if ( capabilities.isWebGL2 === false ) { - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; + extensions.get( 'WEBGL_depth_texture' ); + extensions.get( 'OES_texture_float' ); + extensions.get( 'OES_texture_half_float' ); + extensions.get( 'OES_texture_half_float_linear' ); + extensions.get( 'OES_standard_derivatives' ); + extensions.get( 'OES_element_index_uint' ); + extensions.get( 'OES_vertex_array_object' ); + extensions.get( 'ANGLE_instanced_arrays' ); } - var framebuffer = properties.get( renderTarget ).__webglFramebuffer; - - if ( framebuffer ) { + extensions.get( 'OES_texture_float_linear' ); - var restore = false; + utils = new WebGLUtils( _gl, extensions, capabilities ); - if ( framebuffer !== _currentFramebuffer ) { + state = new WebGLState( _gl, extensions, capabilities ); + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - _gl.bindFramebuffer( 36160, framebuffer ); + info = new WebGLInfo( _gl ); + properties = new WebGLProperties(); + textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); + 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 ); + programCache = new WebGLPrograms( _this, extensions, capabilities, bindingStates ); + materials = new WebGLMaterials( properties ); + renderLists = new WebGLRenderLists( properties ); + renderStates = new WebGLRenderStates(); - restore = true; + background = new WebGLBackground( _this, state, objects, _premultipliedAlpha ); - } + bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); + indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - try { + info.programs = programCache.programs; - var texture = renderTarget.texture; - var textureFormat = texture.format; - var textureType = texture.type; + _this.capabilities = capabilities; + _this.extensions = extensions; + _this.properties = properties; + _this.renderLists = renderLists; + _this.state = state; + _this.info = info; - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { + } - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; + initGLContext(); - } + // xr - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // IE11, Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! ( textureType === HalfFloatType && ( capabilities.isWebGL2 ? extensions.get( 'EXT_color_buffer_float' ) : extensions.get( 'EXT_color_buffer_half_float' ) ) ) ) { + var xr = new WebXRManager( _this, _gl ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; + this.xr = xr; - } + // shadow map - if ( _gl.checkFramebufferStatus( 36160 ) === 36053 ) { + var shadowMap = new WebGLShadowMap( _this, objects, capabilities.maxTextureSize ); - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + this.shadowMap = shadowMap; - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { + // API - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); + this.getContext = function () { - } + return _gl; - } else { + }; - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); + this.getContextAttributes = function () { - } + return _gl.getContextAttributes(); - } finally { + }; - if ( restore ) { + this.forceContextLoss = function () { - _gl.bindFramebuffer( 36160, _currentFramebuffer ); + var extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) { extension.loseContext(); } - } + }; - } + this.forceContextRestore = function () { - } + var extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) { extension.restoreContext(); } }; - this.copyFramebufferToTexture = function ( position, texture, level ) { + this.getPixelRatio = function () { - var width = texture.image.width; - var height = texture.image.height; - var glFormat = utils.convert( texture.format ); + return _pixelRatio; - this.setTexture2D( texture, 0 ); + }; - _gl.copyTexImage2D( 3553, level || 0, glFormat, position.x, position.y, width, height, 0 ); + this.setPixelRatio = function ( value ) { - }; + if ( value === undefined ) { return; } - this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level ) { + _pixelRatio = value; - var width = srcTexture.image.width; - var height = srcTexture.image.height; - var glFormat = utils.convert( dstTexture.format ); - var glType = utils.convert( dstTexture.type ); + this.setSize( _width, _height, false ); - this.setTexture2D( dstTexture, 0 ); + }; - if ( srcTexture.isDataTexture ) { + this.getSize = function ( target ) { - _gl.texSubImage2D( 3553, level || 0, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); + if ( target === undefined ) { - } else { + console.warn( 'WebGLRenderer: .getsize() now requires a Vector2 as an argument' ); - _gl.texSubImage2D( 3553, level || 0, position.x, position.y, glFormat, glType, srcTexture.image ); + target = new Vector2(); } - }; + return target.set( _width, _height ); - } + }; - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + this.setSize = function ( width, height, updateStyle ) { - function FogExp2( color, density ) { + if ( xr.isPresenting ) { - this.name = ''; + console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); + return; - this.color = new Color( color ); - this.density = ( density !== undefined ) ? density : 0.00025; + } - } + _width = width; + _height = height; - FogExp2.prototype.isFogExp2 = true; + _canvas.width = Math.floor( width * _pixelRatio ); + _canvas.height = Math.floor( height * _pixelRatio ); - FogExp2.prototype.clone = function () { + if ( updateStyle !== false ) { - return new FogExp2( this.color, this.density ); + _canvas.style.width = width + 'px'; + _canvas.style.height = height + 'px'; - }; + } - FogExp2.prototype.toJSON = function ( /* meta */ ) { + this.setViewport( 0, 0, width, height ); - return { - type: 'FogExp2', - color: this.color.getHex(), - density: this.density }; - }; + this.getDrawingBufferSize = function ( target ) { - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + if ( target === undefined ) { - function Fog( color, near, far ) { + console.warn( 'WebGLRenderer: .getdrawingBufferSize() now requires a Vector2 as an argument' ); - this.name = ''; + target = new Vector2(); - this.color = new Color( color ); + } - this.near = ( near !== undefined ) ? near : 1; - this.far = ( far !== undefined ) ? far : 1000; + return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); - } + }; - Fog.prototype.isFog = true; + this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - Fog.prototype.clone = function () { + _width = width; + _height = height; - return new Fog( this.color, this.near, this.far ); + _pixelRatio = pixelRatio; - }; + _canvas.width = Math.floor( width * pixelRatio ); + _canvas.height = Math.floor( height * pixelRatio ); - Fog.prototype.toJSON = function ( /* meta */ ) { + this.setViewport( 0, 0, width, height ); - return { - type: 'Fog', - color: this.color.getHex(), - near: this.near, - far: this.far }; - }; + this.getCurrentViewport = function ( target ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + if ( target === undefined ) { - function Scene() { + console.warn( 'WebGLRenderer: .getCurrentViewport() now requires a Vector4 as an argument' ); - Object3D.call( this ); + target = new Vector4(); - this.type = 'Scene'; + } - this.background = null; - this.fog = null; - this.overrideMaterial = null; + return target.copy( _currentViewport ); - this.autoUpdate = true; // checked by the renderer + }; - } + this.getViewport = function ( target ) { - Scene.prototype = Object.assign( Object.create( Object3D.prototype ), { + return target.copy( _viewport ); - constructor: Scene, + }; - copy: function ( source, recursive ) { + this.setViewport = function ( x, y, width, height ) { - Object3D.prototype.copy.call( this, source, recursive ); + if ( x.isVector4 ) { - if ( source.background !== null ) this.background = source.background.clone(); - if ( source.fog !== null ) this.fog = source.fog.clone(); - if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); + _viewport.set( x.x, x.y, x.z, x.w ); - this.autoUpdate = source.autoUpdate; - this.matrixAutoUpdate = source.matrixAutoUpdate; + } else { - return this; + _viewport.set( x, y, width, height ); - }, + } - toJSON: function ( meta ) { + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - var data = Object3D.prototype.toJSON.call( this, meta ); + }; - if ( this.background !== null ) data.object.background = this.background.toJSON( meta ); - if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); + this.getScissor = function ( target ) { - return data; + return target.copy( _scissor ); - } + }; - } ); + this.setScissor = function ( x, y, width, height ) { - /** - * @author benaadams / https://twitter.com/ben_a_adams - */ + if ( x.isVector4 ) { - function InterleavedBuffer( array, stride ) { + _scissor.set( x.x, x.y, x.z, x.w ); - this.array = array; - this.stride = stride; - this.count = array !== undefined ? array.length / stride : 0; + } else { - this.dynamic = false; - this.updateRange = { offset: 0, count: - 1 }; + _scissor.set( x, y, width, height ); - this.version = 0; + } - } + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); - Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', { + }; - set: function ( value ) { + this.getScissorTest = function () { - if ( value === true ) this.version ++; + return _scissorTest; - } + }; - } ); + this.setScissorTest = function ( boolean ) { - Object.assign( InterleavedBuffer.prototype, { + state.setScissorTest( _scissorTest = boolean ); - isInterleavedBuffer: true, + }; - onUploadCallback: function () {}, + this.setOpaqueSort = function ( method ) { - setArray: function ( array ) { + _opaqueSort = method; - if ( Array.isArray( array ) ) { + }; - throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); + this.setTransparentSort = function ( method ) { - } + _transparentSort = method; - this.count = array !== undefined ? array.length / this.stride : 0; - this.array = array; + }; - return this; + // Clearing - }, + this.getClearColor = function () { - setDynamic: function ( value ) { + return background.getClearColor(); - this.dynamic = value; + }; - return this; + this.setClearColor = function () { - }, + background.setClearColor.apply( background, arguments ); - copy: function ( source ) { + }; - this.array = new source.array.constructor( source.array ); - this.count = source.count; - this.stride = source.stride; - this.dynamic = source.dynamic; + this.getClearAlpha = function () { - return this; + return background.getClearAlpha(); - }, + }; - copyAt: function ( index1, attribute, index2 ) { + this.setClearAlpha = function () { - index1 *= this.stride; - index2 *= attribute.stride; + background.setClearAlpha.apply( background, arguments ); - for ( var i = 0, l = this.stride; i < l; i ++ ) { + }; - this.array[ index1 + i ] = attribute.array[ index2 + i ]; + this.clear = function ( color, depth, stencil ) { - } + var bits = 0; - return this; + if ( color === undefined || color ) { bits |= 16384; } + if ( depth === undefined || depth ) { bits |= 256; } + if ( stencil === undefined || stencil ) { bits |= 1024; } - }, + _gl.clear( bits ); - set: function ( value, offset ) { + }; - if ( offset === undefined ) offset = 0; + this.clearColor = function () { - this.array.set( value, offset ); + this.clear( true, false, false ); - return this; + }; - }, + this.clearDepth = function () { - clone: function () { + this.clear( false, true, false ); - return new this.constructor().copy( this ); + }; - }, + this.clearStencil = function () { - onUpload: function ( callback ) { + this.clear( false, false, true ); - this.onUploadCallback = callback; + }; - return this; + // - } + this.dispose = function () { - } ); + _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - /** - * @author benaadams / https://twitter.com/ben_a_adams - */ + renderLists.dispose(); + renderStates.dispose(); + properties.dispose(); + objects.dispose(); + bindingStates.dispose(); - function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) { + xr.dispose(); - this.data = interleavedBuffer; - this.itemSize = itemSize; - this.offset = offset; + animation.stop(); - this.normalized = normalized === true; + }; - } + // Events - Object.defineProperties( InterleavedBufferAttribute.prototype, { + function onContextLost( event ) { - count: { + event.preventDefault(); - get: function () { + console.log( 'THREE.WebGLRenderer: Context Lost.' ); - return this.data.count; + _isContextLost = true; - } + } - }, + function onContextRestore( /* event */ ) { - array: { + console.log( 'THREE.WebGLRenderer: Context Restored.' ); - get: function () { + _isContextLost = false; - return this.data.array; + initGLContext(); - } + } + + function onMaterialDispose( event ) { + + var material = event.target; + + material.removeEventListener( 'dispose', onMaterialDispose ); + + deallocateMaterial( material ); } - } ); + // Buffer deallocation - Object.assign( InterleavedBufferAttribute.prototype, { + function deallocateMaterial( material ) { - isInterleavedBufferAttribute: true, + releaseMaterialProgramReference( material ); - setX: function ( index, x ) { + properties.remove( material ); - this.data.array[ index * this.data.stride + this.offset ] = x; + } - return this; - }, + function releaseMaterialProgramReference( material ) { - setY: function ( index, y ) { + var programInfo = properties.get( material ).program; - this.data.array[ index * this.data.stride + this.offset + 1 ] = y; + if ( programInfo !== undefined ) { - return this; + programCache.releaseProgram( programInfo ); - }, + } - setZ: function ( index, z ) { + } - this.data.array[ index * this.data.stride + this.offset + 2 ] = z; + // Buffer rendering - return this; + function renderObjectImmediate( object, program ) { - }, + object.render( function ( object ) { - setW: function ( index, w ) { + _this.renderBufferImmediate( object, program ); - this.data.array[ index * this.data.stride + this.offset + 3 ] = w; + } ); - return this; + } - }, + this.renderBufferImmediate = function ( object, program ) { - getX: function ( index ) { + bindingStates.initAttributes(); - return this.data.array[ index * this.data.stride + this.offset ]; + var 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(); } - getY: function ( index ) { + var programAttributes = program.getAttributes(); - return this.data.array[ index * this.data.stride + this.offset + 1 ]; + if ( object.hasPositions ) { - }, + _gl.bindBuffer( 34962, buffers.position ); + _gl.bufferData( 34962, object.positionArray, 35048 ); - getZ: function ( index ) { + bindingStates.enableAttribute( programAttributes.position ); + _gl.vertexAttribPointer( programAttributes.position, 3, 5126, false, 0, 0 ); - return this.data.array[ index * this.data.stride + this.offset + 2 ]; + } - }, + if ( object.hasNormals ) { - getW: function ( index ) { + _gl.bindBuffer( 34962, buffers.normal ); + _gl.bufferData( 34962, object.normalArray, 35048 ); - return this.data.array[ index * this.data.stride + this.offset + 3 ]; + bindingStates.enableAttribute( programAttributes.normal ); + _gl.vertexAttribPointer( programAttributes.normal, 3, 5126, false, 0, 0 ); - }, + } - setXY: function ( index, x, y ) { + if ( object.hasUvs ) { - index = index * this.data.stride + this.offset; + _gl.bindBuffer( 34962, buffers.uv ); + _gl.bufferData( 34962, object.uvArray, 35048 ); - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; + bindingStates.enableAttribute( programAttributes.uv ); + _gl.vertexAttribPointer( programAttributes.uv, 2, 5126, false, 0, 0 ); - return this; + } - }, + if ( object.hasColors ) { - setXYZ: function ( index, x, y, z ) { + _gl.bindBuffer( 34962, buffers.color ); + _gl.bufferData( 34962, object.colorArray, 35048 ); - index = index * this.data.stride + this.offset; + bindingStates.enableAttribute( programAttributes.color ); + _gl.vertexAttribPointer( programAttributes.color, 3, 5126, false, 0, 0 ); - this.data.array[ index + 0 ] = x; - this.data.array[ index + 1 ] = y; - this.data.array[ index + 2 ] = z; + } - return this; + bindingStates.disableUnusedAttributes(); - }, + _gl.drawArrays( 4, 0, object.count ); - setXYZW: function ( index, x, y, z, w ) { + object.count = 0; - 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; + this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { - return this; + if ( scene === null ) { scene = _emptyScene; } // renderBufferDirect second parameter used to be fog (could be null) - } + var frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); - } ); + var program = setProgram( camera, scene, material, object ); - /** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * map: new THREE.Texture( ), - * rotation: , - * sizeAttenuation: - * } - */ + state.setMaterial( material, frontFaceCW ); - function SpriteMaterial( parameters ) { + // - Material.call( this ); + var index = geometry.index; + var position = geometry.attributes.position; - this.type = 'SpriteMaterial'; + // - this.color = new Color( 0xffffff ); - this.map = null; + if ( index === null ) { - this.rotation = 0; + if ( position === undefined || position.count === 0 ) { return; } - this.sizeAttenuation = true; + } else if ( index.count === 0 ) { - this.lights = false; - this.transparent = true; + return; - this.setValues( parameters ); + } - } + // - SpriteMaterial.prototype = Object.create( Material.prototype ); - SpriteMaterial.prototype.constructor = SpriteMaterial; - SpriteMaterial.prototype.isSpriteMaterial = true; + var rangeFactor = 1; - SpriteMaterial.prototype.copy = function ( source ) { + if ( material.wireframe === true ) { - Material.prototype.copy.call( this, source ); + index = geometries.getWireframeAttribute( geometry ); + rangeFactor = 2; - this.color.copy( source.color ); - this.map = source.map; + } - this.rotation = source.rotation; + if ( material.morphTargets || material.morphNormals ) { - this.sizeAttenuation = source.sizeAttenuation; + morphtargets.update( object, geometry, material, program ); - return this; + } - }; + bindingStates.setup( object, material, program, geometry, index ); - /** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - */ + var attribute; + var renderer = bufferRenderer; - var geometry; + if ( index !== null ) { - function Sprite( material ) { + attribute = attributes.get( index ); - Object3D.call( this ); + renderer = indexedBufferRenderer; + renderer.setIndex( attribute ); - this.type = 'Sprite'; + } - if ( geometry === undefined ) { + // - geometry = new BufferGeometry(); + var dataCount = ( index !== null ) ? index.count : position.count; - var 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 - ] ); + var rangeStart = geometry.drawRange.start * rangeFactor; + var rangeCount = geometry.drawRange.count * rangeFactor; - var interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); + var groupStart = group !== null ? group.start * rangeFactor : 0; + var groupCount = group !== null ? group.count * rangeFactor : Infinity; - geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); - geometry.addAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); - geometry.addAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); + var drawStart = Math.max( rangeStart, groupStart ); + var drawEnd = Math.min( dataCount, rangeStart + rangeCount, groupStart + groupCount ) - 1; - } + var drawCount = Math.max( 0, drawEnd - drawStart + 1 ); - this.geometry = geometry; - this.material = ( material !== undefined ) ? material : new SpriteMaterial(); + if ( drawCount === 0 ) { return; } - this.center = new Vector2( 0.5, 0.5 ); + // - } + if ( object.isMesh ) { - Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), { + if ( material.wireframe === true ) { - constructor: Sprite, + state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); + renderer.setMode( 1 ); - isSprite: true, + } else { - raycast: ( function () { + renderer.setMode( 4 ); - var intersectPoint = new Vector3(); - var worldScale = new Vector3(); - var mvPosition = new Vector3(); + } + + } else if ( object.isLine ) { - var alignedPosition = new Vector2(); - var rotatedPosition = new Vector2(); - var viewWorldMatrix = new Matrix4(); + var lineWidth = material.linewidth; - var vA = new Vector3(); - var vB = new Vector3(); - var vC = new Vector3(); + if ( lineWidth === undefined ) { lineWidth = 1; } // Not using Line*Material - var uvA = new Vector2(); - var uvB = new Vector2(); - var uvC = new Vector2(); + state.setLineWidth( lineWidth * getTargetPixelRatio() ); - function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { + if ( object.isLineSegments ) { - // compute position in camera space - alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); + renderer.setMode( 1 ); - // to check if rotation is not zero - if ( sin !== undefined ) { + } else if ( object.isLineLoop ) { - rotatedPosition.x = ( cos * alignedPosition.x ) - ( sin * alignedPosition.y ); - rotatedPosition.y = ( sin * alignedPosition.x ) + ( cos * alignedPosition.y ); + renderer.setMode( 2 ); } else { - rotatedPosition.copy( alignedPosition ); + renderer.setMode( 3 ); } + } else if ( object.isPoints ) { + + renderer.setMode( 0 ); - vertexPosition.copy( mvPosition ); - vertexPosition.x += rotatedPosition.x; - vertexPosition.y += rotatedPosition.y; + } else if ( object.isSprite ) { - // transform to world space - vertexPosition.applyMatrix4( viewWorldMatrix ); + renderer.setMode( 4 ); } - return function raycast( raycaster, intersects ) { + if ( object.isInstancedMesh ) { - worldScale.setFromMatrixScale( this.matrixWorld ); - viewWorldMatrix.getInverse( this.modelViewMatrix ).premultiply( this.matrixWorld ); - mvPosition.setFromMatrixPosition( this.modelViewMatrix ); + renderer.renderInstances( drawStart, drawCount, object.count ); - var rotation = this.material.rotation; - var sin, cos; - if ( rotation !== 0 ) { + } else if ( geometry.isInstancedBufferGeometry ) { - cos = Math.cos( rotation ); - sin = Math.sin( rotation ); + var instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount ); - } + renderer.renderInstances( drawStart, drawCount, instanceCount ); - var center = this.center; + } else { - 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 ); + renderer.render( drawStart, drawCount ); - uvA.set( 0, 0 ); - uvB.set( 1, 0 ); - uvC.set( 1, 1 ); + } - // check first triangle - var intersect = raycaster.ray.intersectTriangle( vA, vB, vC, false, intersectPoint ); + }; - if ( intersect === null ) { + // Compile - // check second triangle - transformVertex( vB.set( - 0.5, 0.5, 0 ), mvPosition, center, worldScale, sin, cos ); - uvB.set( 0, 1 ); + this.compile = function ( scene, camera ) { - intersect = raycaster.ray.intersectTriangle( vA, vC, vB, false, intersectPoint ); - if ( intersect === null ) { + currentRenderState = renderStates.get( scene, camera ); + currentRenderState.init(); - return; + scene.traverse( function ( object ) { - } + if ( object.isLight ) { - } + currentRenderState.pushLight( object ); - var distance = raycaster.ray.origin.distanceTo( intersectPoint ); + if ( object.castShadow ) { - if ( distance < raycaster.near || distance > raycaster.far ) return; + currentRenderState.pushShadow( object ); - intersects.push( { + } - distance: distance, - point: intersectPoint.clone(), - uv: Triangle.getUV( intersectPoint, vA, vB, vC, uvA, uvB, uvC, new Vector2() ), - face: null, - object: this + } - } ); + } ); - }; + currentRenderState.setupLights( camera ); - }() ), + var compiled = new WeakMap(); - clone: function () { + scene.traverse( function ( object ) { - return new this.constructor( this.material ).copy( this ); + var material = object.material; - }, + if ( material ) { - copy: function ( source ) { + if ( Array.isArray( material ) ) { - Object3D.prototype.copy.call( this, source ); + for ( var i = 0; i < material.length; i ++ ) { - if ( source.center !== undefined ) this.center.copy( source.center ); + var material2 = material[ i ]; - return this; + if ( compiled.has( material2 ) === false ) { - } + initMaterial( material2, scene, object ); + compiled.set( material2 ); + } - } ); + } - /** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + } else if ( compiled.has( material ) === false ) { - function LOD() { + initMaterial( material, scene, object ); + compiled.set( material ); - Object3D.call( this ); + } - this.type = 'LOD'; + } - Object.defineProperties( this, { - levels: { - enumerable: true, - value: [] - } - } ); + } ); - } + }; - LOD.prototype = Object.assign( Object.create( Object3D.prototype ), { + // Animation Loop - constructor: LOD, + var onAnimationFrameCallback = null; - copy: function ( source ) { + function onAnimationFrame( time ) { - Object3D.prototype.copy.call( this, source, false ); + if ( xr.isPresenting ) { return; } + if ( onAnimationFrameCallback ) { onAnimationFrameCallback( time ); } - var levels = source.levels; + } - for ( var i = 0, l = levels.length; i < l; i ++ ) { + var animation = new WebGLAnimation(); + animation.setAnimationLoop( onAnimationFrame ); - var level = levels[ i ]; + if ( typeof window !== 'undefined' ) { animation.setContext( window ); } - this.addLevel( level.object.clone(), level.distance ); + this.setAnimationLoop = function ( callback ) { - } + onAnimationFrameCallback = callback; + xr.setAnimationLoop( callback ); - return this; + ( callback === null ) ? animation.stop() : animation.start(); - }, + }; - addLevel: function ( object, distance ) { + // Rendering - if ( distance === undefined ) distance = 0; + this.render = function ( scene, camera ) { - distance = Math.abs( distance ); + var renderTarget, forceClear; - var levels = this.levels; + if ( arguments[ 2 ] !== undefined ) { - for ( var l = 0; l < levels.length; l ++ ) { + console.warn( 'THREE.WebGLRenderer.render(): the renderTarget argument has been removed. Use .setRenderTarget() instead.' ); + renderTarget = arguments[ 2 ]; - if ( distance < levels[ l ].distance ) { + } - break; + if ( arguments[ 3 ] !== undefined ) { - } + console.warn( 'THREE.WebGLRenderer.render(): the forceClear argument has been removed. Use .clear() instead.' ); + forceClear = arguments[ 3 ]; } - levels.splice( l, 0, { distance: distance, object: object } ); - - this.add( object ); + if ( camera !== undefined && camera.isCamera !== true ) { - }, + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; - getObjectForDistance: function ( distance ) { + } - var levels = this.levels; + if ( _isContextLost === true ) { return; } - for ( var i = 1, l = levels.length; i < l; i ++ ) { + // reset caching for this frame - if ( distance < levels[ i ].distance ) { + bindingStates.resetDefaultState(); + _currentMaterialId = - 1; + _currentCamera = null; - break; + // update scene graph - } + if ( scene.autoUpdate === true ) { scene.updateMatrixWorld(); } - } + // update camera matrices and frustum - return levels[ i - 1 ].object; + if ( camera.parent === null ) { camera.updateMatrixWorld(); } - }, + if ( xr.enabled === true && xr.isPresenting === true ) { - raycast: ( function () { + camera = xr.getCamera( camera ); - var matrixPosition = new Vector3(); + } - return function raycast( raycaster, intersects ) { + // + if ( scene.isScene === true ) { scene.onBeforeRender( _this, scene, camera, renderTarget || _currentRenderTarget ); } - matrixPosition.setFromMatrixPosition( this.matrixWorld ); + currentRenderState = renderStates.get( scene, camera ); + currentRenderState.init(); - var distance = raycaster.ray.origin.distanceTo( matrixPosition ); + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromProjectionMatrix( _projScreenMatrix ); - this.getObjectForDistance( distance ).raycast( raycaster, intersects ); + _localClippingEnabled = this.localClippingEnabled; + _clippingEnabled = _clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); - }; + currentRenderList = renderLists.get( scene, camera ); + currentRenderList.init(); - }() ), + projectObject( scene, camera, 0, _this.sortObjects ); - update: function () { + currentRenderList.finish(); - var v1 = new Vector3(); - var v2 = new Vector3(); + if ( _this.sortObjects === true ) { - return function update( camera ) { + currentRenderList.sort( _opaqueSort, _transparentSort ); - var levels = this.levels; + } - if ( levels.length > 1 ) { + // - v1.setFromMatrixPosition( camera.matrixWorld ); - v2.setFromMatrixPosition( this.matrixWorld ); + if ( _clippingEnabled === true ) { _clipping.beginShadows(); } - var distance = v1.distanceTo( v2 ); + var shadowsArray = currentRenderState.state.shadowsArray; - levels[ 0 ].object.visible = true; + shadowMap.render( shadowsArray, scene, camera ); - for ( var i = 1, l = levels.length; i < l; i ++ ) { + currentRenderState.setupLights( camera ); - if ( distance >= levels[ i ].distance ) { + if ( _clippingEnabled === true ) { _clipping.endShadows(); } - levels[ i - 1 ].object.visible = false; - levels[ i ].object.visible = true; + // - } else { + if ( this.info.autoReset === true ) { this.info.reset(); } - break; + if ( renderTarget !== undefined ) { - } + this.setRenderTarget( renderTarget ); - } + } - for ( ; i < l; i ++ ) { + // - levels[ i ].object.visible = false; + background.render( currentRenderList, scene, camera, forceClear ); - } + // render scene - } + var opaqueObjects = currentRenderList.opaque; + var transparentObjects = currentRenderList.transparent; - }; + if ( opaqueObjects.length > 0 ) { renderObjects( opaqueObjects, scene, camera ); } + if ( transparentObjects.length > 0 ) { renderObjects( transparentObjects, scene, camera ); } - }(), + // - toJSON: function ( meta ) { + if ( scene.isScene === true ) { scene.onAfterRender( _this, scene, camera ); } - var data = Object3D.prototype.toJSON.call( this, meta ); + // - data.object.levels = []; + if ( _currentRenderTarget !== null ) { - var levels = this.levels; + // Generate mipmap if we're using any kind of mipmap filtering - for ( var i = 0, l = levels.length; i < l; i ++ ) { + textures.updateRenderTargetMipmap( _currentRenderTarget ); - var level = levels[ i ]; + // resolve multisample renderbuffers to a single-sample texture if necessary - data.object.levels.push( { - object: level.object.uuid, - distance: level.distance - } ); + textures.updateMultisampleRenderTarget( _currentRenderTarget ); } - return data; + // 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 ); - /** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author michael guerrero / http://realitymeltdown.com - * @author ikerr / http://verold.com - */ + // _gl.finish(); - function Skeleton( bones, boneInverses ) { + currentRenderList = null; + currentRenderState = null; - // copy the bone array + }; - bones = bones || []; + function projectObject( object, camera, groupOrder, sortObjects ) { - this.bones = bones.slice( 0 ); - this.boneMatrices = new Float32Array( this.bones.length * 16 ); + if ( object.visible === false ) { return; } - // use the supplied bone inverses or calculate the inverses + var visible = object.layers.test( camera.layers ); - if ( boneInverses === undefined ) { + if ( visible ) { - this.calculateInverses(); + if ( object.isGroup ) { - } else { + groupOrder = object.renderOrder; - if ( this.bones.length === boneInverses.length ) { + } else if ( object.isLOD ) { - this.boneInverses = boneInverses.slice( 0 ); + if ( object.autoUpdate === true ) { object.update( camera ); } - } else { + } else if ( object.isLight ) { - console.warn( 'THREE.Skeleton boneInverses is the wrong length.' ); + currentRenderState.pushLight( object ); - this.boneInverses = []; + if ( object.castShadow ) { - for ( var i = 0, il = this.bones.length; i < il; i ++ ) { + currentRenderState.pushShadow( object ); - this.boneInverses.push( new Matrix4() ); + } - } + } else if ( object.isSprite ) { - } + if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - } + if ( sortObjects ) { - } + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - Object.assign( Skeleton.prototype, { + } - calculateInverses: function () { + var geometry = objects.update( object ); + var material = object.material; - this.boneInverses = []; + if ( material.visible ) { - for ( var i = 0, il = this.bones.length; i < il; i ++ ) { + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - var inverse = new Matrix4(); + } - if ( this.bones[ i ] ) { + } - inverse.getInverse( this.bones[ i ].matrixWorld ); + } else if ( object.isImmediateRenderObject ) { - } + if ( sortObjects ) { - this.boneInverses.push( inverse ); + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - } + } - }, + currentRenderList.push( object, null, object.material, groupOrder, _vector3.z, null ); - pose: function () { + } else if ( object.isMesh || object.isLine || object.isPoints ) { - var bone, i, il; + if ( object.isSkinnedMesh ) { - // recover the bind-time world matrices + // update skeleton only once in a frame - for ( i = 0, il = this.bones.length; i < il; i ++ ) { + if ( object.skeleton.frame !== info.render.frame ) { - bone = this.bones[ i ]; + object.skeleton.update(); + object.skeleton.frame = info.render.frame; - if ( bone ) { + } - bone.matrixWorld.getInverse( this.boneInverses[ i ] ); + } - } + if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - } + if ( sortObjects ) { - // compute the local matrices, positions, rotations and scales + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - for ( i = 0, il = this.bones.length; i < il; i ++ ) { + } - bone = this.bones[ i ]; + var geometry$1 = objects.update( object ); + var material$1 = object.material; - if ( bone ) { + if ( Array.isArray( material$1 ) ) { - if ( bone.parent && bone.parent.isBone ) { + var groups = geometry$1.groups; - bone.matrix.getInverse( bone.parent.matrixWorld ); - bone.matrix.multiply( bone.matrixWorld ); + for ( var i = 0, l = groups.length; i < l; i ++ ) { - } else { + var group = groups[ i ]; + var groupMaterial = material$1[ group.materialIndex ]; + + if ( groupMaterial && groupMaterial.visible ) { - bone.matrix.copy( bone.matrixWorld ); + currentRenderList.push( object, geometry$1, groupMaterial, groupOrder, _vector3.z, group ); - } + } + + } + + } else if ( material$1.visible ) { + + currentRenderList.push( object, geometry$1, material$1, groupOrder, _vector3.z, null ); + + } - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + } } } - }, + var children = object.children; - update: ( function () { + for ( var i$1 = 0, l$1 = children.length; i$1 < l$1; i$1 ++ ) { - var offsetMatrix = new Matrix4(); - var identityMatrix = new Matrix4(); + projectObject( children[ i$1 ], camera, groupOrder, sortObjects ); - return function update() { + } - var bones = this.bones; - var boneInverses = this.boneInverses; - var boneMatrices = this.boneMatrices; - var boneTexture = this.boneTexture; + } - // flatten bone matrices to array + function renderObjects( renderList, scene, camera ) { - for ( var i = 0, il = bones.length; i < il; i ++ ) { + var overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - // compute the offset between the current and the original transform + for ( var i = 0, l = renderList.length; i < l; i ++ ) { - var matrix = bones[ i ] ? bones[ i ].matrixWorld : identityMatrix; + var renderItem = renderList[ i ]; - offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); - offsetMatrix.toArray( boneMatrices, i * 16 ); + var object = renderItem.object; + var geometry = renderItem.geometry; + var material = overrideMaterial === null ? renderItem.material : overrideMaterial; + var group = renderItem.group; - } + if ( camera.isArrayCamera ) { - if ( boneTexture !== undefined ) { + _currentArrayCamera = camera; - boneTexture.needsUpdate = true; + var cameras = camera.cameras; - } + for ( var j = 0, jl = cameras.length; j < jl; j ++ ) { - }; + var camera2 = cameras[ j ]; - } )(), + if ( object.layers.test( camera2.layers ) ) { - clone: function () { + state.viewport( _currentViewport.copy( camera2.viewport ) ); - return new Skeleton( this.bones, this.boneInverses ); + currentRenderState.setupLights( camera2 ); - }, + renderObject( object, scene, camera2, geometry, material, group ); - getBoneByName: function ( name ) { + } - for ( var i = 0, il = this.bones.length; i < il; i ++ ) { + } - var bone = this.bones[ i ]; + } else { - if ( bone.name === name ) { + _currentArrayCamera = null; - return bone; + renderObject( object, scene, camera, geometry, material, group ); } } - return undefined; - } - } ); + function renderObject( object, scene, camera, geometry, material, group ) { - /** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author ikerr / http://verold.com - */ + object.onBeforeRender( _this, scene, camera, geometry, material, group ); + currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); - function Bone() { + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - Object3D.call( this ); + if ( object.isImmediateRenderObject ) { - this.type = 'Bone'; + var program = setProgram( camera, scene, material, object ); - } + state.setMaterial( material ); - Bone.prototype = Object.assign( Object.create( Object3D.prototype ), { + bindingStates.reset(); - constructor: Bone, + renderObjectImmediate( object, program ); - isBone: true + } else { - } ); + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - /** - * @author mikael emtinger / http://gomo.se/ - * @author alteredq / http://alteredqualia.com/ - * @author ikerr / http://verold.com - */ + } - function SkinnedMesh( geometry, material ) { + object.onAfterRender( _this, scene, camera, geometry, material, group ); + currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); - Mesh.call( this, geometry, material ); + } - this.type = 'SkinnedMesh'; + function initMaterial( material, scene, object ) { - this.bindMode = 'attached'; - this.bindMatrix = new Matrix4(); - this.bindMatrixInverse = new Matrix4(); + if ( scene.isScene !== true ) { scene = _emptyScene; } // scene could be a Mesh, Line, Points, ... - var bones = this.initBones(); - var skeleton = new Skeleton( bones ); + var materialProperties = properties.get( material ); - this.bind( skeleton, this.matrixWorld ); + var lights = currentRenderState.state.lights; + var shadowsArray = currentRenderState.state.shadowsArray; - this.normalizeSkinWeights(); + var lightsStateVersion = lights.state.version; - } + var parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, _clipping.numPlanes, _clipping.numIntersection, object ); + var programCacheKey = programCache.getProgramCacheKey( parameters ); - SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { + var program = materialProperties.program; + var programChange = true; - constructor: SkinnedMesh, + if ( program === undefined ) { - isSkinnedMesh: true, + // new material + material.addEventListener( 'dispose', onMaterialDispose ); + + } else if ( program.cacheKey !== programCacheKey ) { - initBones: function () { + // changed glsl or parameters + releaseMaterialProgramReference( material ); - var bones = [], bone, gbone; - var i, il; + } else if ( materialProperties.lightsStateVersion !== lightsStateVersion ) { - if ( this.geometry && this.geometry.bones !== undefined ) { + materialProperties.lightsStateVersion = lightsStateVersion; - // first, create array of 'Bone' objects from geometry data + programChange = false; - for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) { + } else if ( parameters.shaderID !== undefined ) { - gbone = this.geometry.bones[ i ]; + // same glsl and uniform list + return; - // create new 'Bone' object + } else { - bone = new Bone(); - bones.push( bone ); + // only rebuild uniform list + programChange = false; - // apply values + } - bone.name = gbone.name; - bone.position.fromArray( gbone.pos ); - bone.quaternion.fromArray( gbone.rotq ); - if ( gbone.scl !== undefined ) bone.scale.fromArray( gbone.scl ); + if ( programChange ) { - } + parameters.uniforms = programCache.getUniforms( material, parameters ); - // second, create bone hierarchy + material.onBeforeCompile( parameters, _this ); - for ( i = 0, il = this.geometry.bones.length; i < il; i ++ ) { + program = programCache.acquireProgram( parameters, programCacheKey ); - gbone = this.geometry.bones[ i ]; + materialProperties.program = program; + materialProperties.uniforms = parameters.uniforms; + materialProperties.outputEncoding = parameters.outputEncoding; - if ( ( gbone.parent !== - 1 ) && ( gbone.parent !== null ) && ( bones[ gbone.parent ] !== undefined ) ) { + } - // subsequent bones in the hierarchy + var programAttributes = program.getAttributes(); - bones[ gbone.parent ].add( bones[ i ] ); + if ( material.morphTargets ) { - } else { + material.numSupportedMorphTargets = 0; - // topmost bone, immediate child of the skinned mesh + for ( var i = 0; i < _this.maxMorphTargets; i ++ ) { + + if ( programAttributes[ 'morphTarget' + i ] >= 0 ) { - this.add( bones[ i ] ); + material.numSupportedMorphTargets ++; } @@ -25656,4215 +25855,3991 @@ } - // now the bones are part of the scene graph and children of the skinned mesh. - // let's update the corresponding matrices - - this.updateMatrixWorld( true ); + if ( material.morphNormals ) { - return bones; + material.numSupportedMorphNormals = 0; - }, + for ( var i$1 = 0; i$1 < _this.maxMorphNormals; i$1 ++ ) { - bind: function ( skeleton, bindMatrix ) { + if ( programAttributes[ 'morphNormal' + i$1 ] >= 0 ) { - this.skeleton = skeleton; + material.numSupportedMorphNormals ++; - if ( bindMatrix === undefined ) { + } - this.updateMatrixWorld( true ); + } - this.skeleton.calculateInverses(); + } - bindMatrix = this.matrixWorld; + var uniforms = materialProperties.uniforms; - } + if ( ! material.isShaderMaterial && + ! material.isRawShaderMaterial || + material.clipping === true ) { - this.bindMatrix.copy( bindMatrix ); - this.bindMatrixInverse.getInverse( bindMatrix ); + materialProperties.numClippingPlanes = _clipping.numPlanes; + materialProperties.numIntersection = _clipping.numIntersection; + uniforms.clippingPlanes = _clipping.uniform; - }, + } - pose: function () { + materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; + materialProperties.fog = scene.fog; - this.skeleton.pose(); + // store the light setup it was created for - }, + materialProperties.needsLights = materialNeedsLights( material ); + materialProperties.lightsStateVersion = lightsStateVersion; - normalizeSkinWeights: function () { + if ( materialProperties.needsLights ) { - var scale, i; + // wire up the material to this renderer's lighting state - if ( this.geometry && this.geometry.isGeometry ) { + 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.pointLights.value = lights.state.point; + uniforms.pointLightShadows.value = lights.state.pointShadow; + uniforms.hemisphereLights.value = lights.state.hemi; - for ( i = 0; i < this.geometry.skinWeights.length; i ++ ) { + 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 - var sw = this.geometry.skinWeights[ i ]; + } - scale = 1.0 / sw.manhattanLength(); + var progUniforms = materialProperties.program.getUniforms(), + uniformsList = + WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); - if ( scale !== Infinity ) { + materialProperties.uniformsList = uniformsList; - sw.multiplyScalar( scale ); + } - } else { + function setProgram( camera, scene, material, object ) { - sw.set( 1, 0, 0, 0 ); // do something reasonable + if ( scene.isScene !== true ) { scene = _emptyScene; } // scene could be a Mesh, Line, Points, ... - } + textures.resetTextureUnits(); - } + var fog = scene.fog; + var environment = material.isMeshStandardMaterial ? scene.environment : null; + var encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : _currentRenderTarget.texture.encoding; - } else if ( this.geometry && this.geometry.isBufferGeometry ) { + var materialProperties = properties.get( material ); + var lights = currentRenderState.state.lights; - var vec = new Vector4(); + if ( _clippingEnabled === true ) { - var skinWeight = this.geometry.attributes.skinWeight; + if ( _localClippingEnabled === true || camera !== _currentCamera ) { - for ( i = 0; i < skinWeight.count; i ++ ) { + var useCache = + camera === _currentCamera && + material.id === _currentMaterialId; - vec.x = skinWeight.getX( i ); - vec.y = skinWeight.getY( i ); - vec.z = skinWeight.getZ( i ); - vec.w = skinWeight.getW( i ); + // we might want to call this function with some ClippingGroup + // object instead of the material, once it becomes feasible + // (#8465, #8379) + _clipping.setState( + material.clippingPlanes, material.clipIntersection, material.clipShadows, + camera, materialProperties, useCache ); - scale = 1.0 / vec.manhattanLength(); + } - if ( scale !== Infinity ) { + } - vec.multiplyScalar( scale ); + if ( material.version === materialProperties.__version ) { - } else { + if ( materialProperties.program === undefined ) { - vec.set( 1, 0, 0, 0 ); // do something reasonable + initMaterial( material, scene, object ); - } + } else if ( material.fog && materialProperties.fog !== fog ) { - skinWeight.setXYZW( i, vec.x, vec.y, vec.z, vec.w ); + initMaterial( material, scene, object ); - } + } else if ( materialProperties.environment !== environment ) { - } + initMaterial( material, scene, object ); - }, + } else if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { - updateMatrixWorld: function ( force ) { + initMaterial( material, scene, object ); - Mesh.prototype.updateMatrixWorld.call( this, force ); + } else if ( materialProperties.numClippingPlanes !== undefined && + ( materialProperties.numClippingPlanes !== _clipping.numPlanes || + materialProperties.numIntersection !== _clipping.numIntersection ) ) { - if ( this.bindMode === 'attached' ) { + initMaterial( material, scene, object ); - this.bindMatrixInverse.getInverse( this.matrixWorld ); + } else if ( materialProperties.outputEncoding !== encoding ) { - } else if ( this.bindMode === 'detached' ) { + initMaterial( material, scene, object ); - this.bindMatrixInverse.getInverse( this.bindMatrix ); + } } else { - console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); + initMaterial( material, scene, object ); + materialProperties.__version = material.version; } - }, + var refreshProgram = false; + var refreshMaterial = false; + var refreshLights = false; - clone: function () { + var program = materialProperties.program, + p_uniforms = program.getUniforms(), + m_uniforms = materialProperties.uniforms; - return new this.constructor( this.geometry, this.material ).copy( this ); + if ( state.useProgram( program.program ) ) { - } + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; - } ); + } - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * linewidth: , - * linecap: "round", - * linejoin: "round" - * } - */ + if ( material.id !== _currentMaterialId ) { - function LineBasicMaterial( parameters ) { + _currentMaterialId = material.id; - Material.call( this ); + refreshMaterial = true; - this.type = 'LineBasicMaterial'; + } - this.color = new Color( 0xffffff ); + if ( refreshProgram || _currentCamera !== camera ) { - this.linewidth = 1; - this.linecap = 'round'; - this.linejoin = 'round'; + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); - this.lights = false; + if ( capabilities.logarithmicDepthBuffer ) { - this.setValues( parameters ); + p_uniforms.setValue( _gl, 'logDepthBufFC', + 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - } + } - LineBasicMaterial.prototype = Object.create( Material.prototype ); - LineBasicMaterial.prototype.constructor = LineBasicMaterial; + if ( _currentCamera !== camera ) { - LineBasicMaterial.prototype.isLineBasicMaterial = true; + _currentCamera = camera; - LineBasicMaterial.prototype.copy = function ( source ) { + // 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: - Material.prototype.copy.call( this, source ); + refreshMaterial = true; // set to true on material change + refreshLights = true; // remains set until update done - this.color.copy( source.color ); + } - this.linewidth = source.linewidth; - this.linecap = source.linecap; - this.linejoin = source.linejoin; + // load material specific uniforms + // (shader material also gets them for the sake of genericity) - return this; + if ( material.isShaderMaterial || + material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshStandardMaterial || + material.envMap ) { - }; + var uCamPos = p_uniforms.map.cameraPosition; - /** - * @author mrdoob / http://mrdoob.com/ - */ + if ( uCamPos !== undefined ) { - function Line( geometry, material, mode ) { + uCamPos.setValue( _gl, + _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - if ( mode === 1 ) { + } - console.error( 'THREE.Line: parameter THREE.LinePieces no longer supported. Use THREE.LineSegments instead.' ); + } - } + if ( material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial ) { - Object3D.call( this ); + p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); - this.type = 'Line'; + } - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new LineBasicMaterial( { color: Math.random() * 0xffffff } ); + if ( material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial || + material.isShadowMaterial || + material.skinning ) { - } + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - Line.prototype = Object.assign( Object.create( Object3D.prototype ), { + } - constructor: Line, + } - isLine: true, + // 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 ( material.skinning ) { - computeLineDistances: ( function () { + p_uniforms.setOptional( _gl, object, 'bindMatrix' ); + p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - var start = new Vector3(); - var end = new Vector3(); + var skeleton = object.skeleton; - return function computeLineDistances() { + if ( skeleton ) { - var geometry = this.geometry; + var bones = skeleton.bones; + + if ( capabilities.floatVertexTextures ) { - if ( geometry.isBufferGeometry ) { + if ( skeleton.boneTexture === undefined ) { - // we assume non-indexed geometry + // 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) - if ( geometry.index === null ) { - var positionAttribute = geometry.attributes.position; - var lineDistances = [ 0 ]; + var size = Math.sqrt( bones.length * 4 ); // 4 pixels needed for 1 matrix + size = MathUtils.ceilPowerOfTwo( size ); + size = Math.max( size, 4 ); - for ( var i = 1, l = positionAttribute.count; i < l; i ++ ) { + var boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel + boneMatrices.set( skeleton.boneMatrices ); // copy current values - start.fromBufferAttribute( positionAttribute, i - 1 ); - end.fromBufferAttribute( positionAttribute, i ); + var boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); - lineDistances[ i ] = lineDistances[ i - 1 ]; - lineDistances[ i ] += start.distanceTo( end ); + skeleton.boneMatrices = boneMatrices; + skeleton.boneTexture = boneTexture; + skeleton.boneTextureSize = size; } - geometry.addAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); + p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); + p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); } else { - console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); + p_uniforms.setOptional( _gl, skeleton, 'boneMatrices' ); } - } else if ( geometry.isGeometry ) { - - var vertices = geometry.vertices; - var lineDistances = geometry.lineDistances; + } - lineDistances[ 0 ] = 0; + } - for ( var i = 1, l = vertices.length; i < l; i ++ ) { + if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { - lineDistances[ i ] = lineDistances[ i - 1 ]; - lineDistances[ i ] += vertices[ i - 1 ].distanceTo( vertices[ i ] ); + materialProperties.receiveShadow = object.receiveShadow; + p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); - } + } - } + if ( refreshMaterial ) { - return this; + p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - }; + if ( materialProperties.needsLights ) { - }() ), + // the current material requires lighting info - raycast: ( function () { + // 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 - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); + markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - return function raycast( raycaster, intersects ) { + } - var precision = raycaster.linePrecision; + // refresh uniforms common to several materials - var geometry = this.geometry; - var matrixWorld = this.matrixWorld; + if ( fog && material.fog ) { - // Checking boundingSphere distance to ray + materials.refreshFogUniforms( m_uniforms, fog ); - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + } - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); - sphere.radius += precision; + materials.refreshMaterialUniforms( m_uniforms, material, environment, _pixelRatio, _height ); - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + // RectAreaLight Texture + // TODO (mrdoob): Find a nicer implementation - // + if ( m_uniforms.ltc_1 !== undefined ) { m_uniforms.ltc_1.value = UniformsLib.LTC_1; } + if ( m_uniforms.ltc_2 !== undefined ) { m_uniforms.ltc_2.value = UniformsLib.LTC_2; } - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); - var localPrecision = precision / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - var localPrecisionSq = localPrecision * localPrecision; + } - var vStart = new Vector3(); - var vEnd = new Vector3(); - var interSegment = new Vector3(); - var interRay = new Vector3(); - var step = ( this && this.isLineSegments ) ? 2 : 1; + if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - if ( geometry.isBufferGeometry ) { + WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); + material.uniformsNeedUpdate = false; - var index = geometry.index; - var attributes = geometry.attributes; - var positions = attributes.position.array; + } - if ( index !== null ) { + if ( material.isSpriteMaterial ) { - var indices = index.array; + p_uniforms.setValue( _gl, 'center', object.center ); - for ( var i = 0, l = indices.length - 1; i < l; i += step ) { + } - var a = indices[ i ]; - var b = indices[ i + 1 ]; + // common matrices - vStart.fromArray( positions, a * 3 ); - vEnd.fromArray( positions, b * 3 ); + p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); + p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); + p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); + return program; - if ( distSq > localPrecisionSq ) continue; + } - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + // If uniforms are marked as clean, they don't need to be loaded to the GPU. - var distance = raycaster.ray.origin.distanceTo( interRay ); + function markUniformsLightsNeedsUpdate( uniforms, value ) { - if ( distance < raycaster.near || distance > raycaster.far ) continue; + uniforms.ambientLightColor.needsUpdate = value; + uniforms.lightProbe.needsUpdate = value; - intersects.push( { + 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; - 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 + } - } ); + function materialNeedsLights( material ) { - } + return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || + material.isMeshStandardMaterial || material.isShadowMaterial || + ( material.isShaderMaterial && material.lights === true ); - } else { + } - for ( var i = 0, l = positions.length / 3 - 1; i < l; i += step ) { + // + this.setFramebuffer = function ( value ) { - vStart.fromArray( positions, 3 * i ); - vEnd.fromArray( positions, 3 * i + 3 ); + if ( _framebuffer !== value && _currentRenderTarget === null ) { _gl.bindFramebuffer( 36160, value ); } - var distSq = ray.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); + _framebuffer = value; - if ( distSq > localPrecisionSq ) continue; + }; - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + this.getActiveCubeFace = function () { - var distance = raycaster.ray.origin.distanceTo( interRay ); + return _currentActiveCubeFace; - if ( distance < raycaster.near || distance > raycaster.far ) continue; + }; - intersects.push( { + this.getActiveMipmapLevel = function () { - 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 + return _currentActiveMipmapLevel; - } ); + }; - } + this.getRenderTarget = function () { - } + return _currentRenderTarget; - } else if ( geometry.isGeometry ) { + }; - var vertices = geometry.vertices; - var nbVertices = vertices.length; + this.setRenderTarget = function ( renderTarget, activeCubeFace, activeMipmapLevel ) { - for ( var i = 0; i < nbVertices - 1; i += step ) { + _currentRenderTarget = renderTarget; + _currentActiveCubeFace = activeCubeFace; + _currentActiveMipmapLevel = activeMipmapLevel; - var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); + if ( renderTarget && properties.get( renderTarget ).__webglFramebuffer === undefined ) { - if ( distSq > localPrecisionSq ) continue; + textures.setupRenderTarget( renderTarget ); - interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation + } - var distance = raycaster.ray.origin.distanceTo( interRay ); + var framebuffer = _framebuffer; + var isCube = false; - if ( distance < raycaster.near || distance > raycaster.far ) continue; + if ( renderTarget ) { - intersects.push( { + var _webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - 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 + if ( renderTarget.isWebGLCubeRenderTarget ) { - } ); + framebuffer = _webglFramebuffer[ activeCubeFace || 0 ]; + isCube = true; - } + } else if ( renderTarget.isWebGLMultisampleRenderTarget ) { - } + framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; - }; + } else { - }() ), + framebuffer = _webglFramebuffer; - copy: function ( source ) { + } - Object3D.prototype.copy.call( this, source ); + _currentViewport.copy( renderTarget.viewport ); + _currentScissor.copy( renderTarget.scissor ); + _currentScissorTest = renderTarget.scissorTest; - this.geometry.copy( source.geometry ); - this.material.copy( source.material ); + } else { - return this; + _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); + _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); + _currentScissorTest = _scissorTest; - }, + } - clone: function () { + if ( _currentFramebuffer !== framebuffer ) { - return new this.constructor().copy( this ); - - } + _gl.bindFramebuffer( 36160, framebuffer ); + _currentFramebuffer = framebuffer; - } ); + } - /** - * @author mrdoob / http://mrdoob.com/ - */ + state.viewport( _currentViewport ); + state.scissor( _currentScissor ); + state.setScissorTest( _currentScissorTest ); - function LineSegments( geometry, material ) { + if ( isCube ) { - Line.call( this, geometry, material ); + var textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( 36160, 36064, 34069 + ( activeCubeFace || 0 ), textureProperties.__webglTexture, activeMipmapLevel || 0 ); - this.type = 'LineSegments'; + } - } + }; - LineSegments.prototype = Object.assign( Object.create( Line.prototype ), { + this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { - constructor: LineSegments, + if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - isLineSegments: true, + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - computeLineDistances: ( function () { + } - var start = new Vector3(); - var end = new Vector3(); + var framebuffer = properties.get( renderTarget ).__webglFramebuffer; - return function computeLineDistances() { + if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { - var geometry = this.geometry; + framebuffer = framebuffer[ activeCubeFaceIndex ]; - if ( geometry.isBufferGeometry ) { + } - // we assume non-indexed geometry + if ( framebuffer ) { - if ( geometry.index === null ) { + var restore = false; - var positionAttribute = geometry.attributes.position; - var lineDistances = []; + if ( framebuffer !== _currentFramebuffer ) { - for ( var i = 0, l = positionAttribute.count; i < l; i += 2 ) { + _gl.bindFramebuffer( 36160, framebuffer ); - start.fromBufferAttribute( positionAttribute, i ); - end.fromBufferAttribute( positionAttribute, i + 1 ); + restore = true; - lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; - lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end ); + } - } + try { - geometry.addAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); + var texture = renderTarget.texture; + var textureFormat = texture.format; + var textureType = texture.type; - } else { + if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { - console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); + return; } - } else if ( geometry.isGeometry ) { - - var vertices = geometry.vertices; - var lineDistances = geometry.lineDistances; - - for ( var i = 0, l = vertices.length; i < l; i += 2 ) { - - start.copy( vertices[ i ] ); - end.copy( vertices[ i + 1 ] ); + if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // IE11, Edge and Chrome Mac < 52 (#9513) + ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.get( 'OES_texture_float' ) || extensions.get( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox + ! ( textureType === HalfFloatType && ( capabilities.isWebGL2 ? extensions.get( 'EXT_color_buffer_float' ) : extensions.get( 'EXT_color_buffer_half_float' ) ) ) ) { - lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; - lineDistances[ i + 1 ] = lineDistances[ i ] + start.distanceTo( end ); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); + return; } - } - - return this; + 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 ); - /** - * @author mgreter / http://github.com/mgreter - */ + } - function LineLoop( geometry, material ) { + } else { - Line.call( this, geometry, material ); + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.' ); - this.type = 'LineLoop'; + } - } + } finally { - LineLoop.prototype = Object.assign( Object.create( Line.prototype ), { + if ( restore ) { - constructor: LineLoop, + _gl.bindFramebuffer( 36160, _currentFramebuffer ); - isLineLoop: true, + } - } ); + } - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * map: new THREE.Texture( ), - * - * size: , - * sizeAttenuation: - * - * morphTargets: - * } - */ + } - function PointsMaterial( parameters ) { + }; - Material.call( this ); + this.copyFramebufferToTexture = function ( position, texture, level ) { - this.type = 'PointsMaterial'; + if ( level === undefined ) { level = 0; } - this.color = new Color( 0xffffff ); + var levelScale = Math.pow( 2, - level ); + var width = Math.floor( texture.image.width * levelScale ); + var height = Math.floor( texture.image.height * levelScale ); + var glFormat = utils.convert( texture.format ); - this.map = null; + textures.setTexture2D( texture, 0 ); - this.size = 1; - this.sizeAttenuation = true; + _gl.copyTexImage2D( 3553, level, glFormat, position.x, position.y, width, height, 0 ); - this.morphTargets = false; + state.unbindTexture(); - this.lights = false; + }; - this.setValues( parameters ); + this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level ) { - } + if ( level === undefined ) { level = 0; } - PointsMaterial.prototype = Object.create( Material.prototype ); - PointsMaterial.prototype.constructor = PointsMaterial; + var width = srcTexture.image.width; + var height = srcTexture.image.height; + var glFormat = utils.convert( dstTexture.format ); + var glType = utils.convert( dstTexture.type ); - PointsMaterial.prototype.isPointsMaterial = true; + textures.setTexture2D( dstTexture, 0 ); - PointsMaterial.prototype.copy = function ( source ) { + // 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 ); - Material.prototype.copy.call( this, source ); + if ( srcTexture.isDataTexture ) { - this.color.copy( source.color ); + _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - this.map = source.map; + } else { - this.size = source.size; - this.sizeAttenuation = source.sizeAttenuation; + if ( srcTexture.isCompressedTexture ) { - this.morphTargets = source.morphTargets; + _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); - return this; + } else { - }; + _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image ); - /** - * @author alteredq / http://alteredqualia.com/ - */ + } - function Points( geometry, material ) { + } - Object3D.call( this ); + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) { _gl.generateMipmap( 3553 ); } - this.type = 'Points'; + state.unbindTexture(); - this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); - this.material = material !== undefined ? material : new PointsMaterial( { color: Math.random() * 0xffffff } ); + }; - } + this.initTexture = function ( texture ) { - Points.prototype = Object.assign( Object.create( Object3D.prototype ), { + textures.setTexture2D( texture, 0 ); - constructor: Points, + state.unbindTexture(); - isPoints: true, + }; - raycast: ( function () { + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - var inverseMatrix = new Matrix4(); - var ray = new Ray(); - var sphere = new Sphere(); + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); // eslint-disable-line no-undef - return function raycast( raycaster, intersects ) { + } - var object = this; - var geometry = this.geometry; - var matrixWorld = this.matrixWorld; - var threshold = raycaster.params.Points.threshold; + } - // Checking boundingSphere distance to ray + function WebGL1Renderer( parameters ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + WebGLRenderer.call( this, parameters ); - sphere.copy( geometry.boundingSphere ); - sphere.applyMatrix4( matrixWorld ); - sphere.radius += threshold; + } - if ( raycaster.ray.intersectsSphere( sphere ) === false ) return; + WebGL1Renderer.prototype = Object.assign( Object.create( WebGLRenderer.prototype ), { - // + constructor: WebGL1Renderer, - inverseMatrix.getInverse( matrixWorld ); - ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); + isWebGL1Renderer: true - var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); - var localThresholdSq = localThreshold * localThreshold; - var position = new Vector3(); - var intersectPoint = new Vector3(); + } ); - function testPoint( point, index ) { + function FogExp2( color, density ) { - var rayPointDistanceSq = ray.distanceSqToPoint( point ); + this.name = ''; - if ( rayPointDistanceSq < localThresholdSq ) { + this.color = new Color( color ); + this.density = ( density !== undefined ) ? density : 0.00025; - ray.closestPointToPoint( point, intersectPoint ); - intersectPoint.applyMatrix4( matrixWorld ); + } - var distance = raycaster.ray.origin.distanceTo( intersectPoint ); + Object.assign( FogExp2.prototype, { - if ( distance < raycaster.near || distance > raycaster.far ) return; + isFogExp2: true, - intersects.push( { + clone: function () { - distance: distance, - distanceToRay: Math.sqrt( rayPointDistanceSq ), - point: intersectPoint.clone(), - index: index, - face: null, - object: object + return new FogExp2( this.color, this.density ); - } ); + }, - } + toJSON: function ( /* meta */ ) { - } + return { + type: 'FogExp2', + color: this.color.getHex(), + density: this.density + }; - if ( geometry.isBufferGeometry ) { + } - var index = geometry.index; - var attributes = geometry.attributes; - var positions = attributes.position.array; + } ); - if ( index !== null ) { + function Fog( color, near, far ) { - var indices = index.array; + this.name = ''; - for ( var i = 0, il = indices.length; i < il; i ++ ) { + this.color = new Color( color ); - var a = indices[ i ]; + this.near = ( near !== undefined ) ? near : 1; + this.far = ( far !== undefined ) ? far : 1000; - position.fromArray( positions, a * 3 ); + } - testPoint( position, a ); + Object.assign( Fog.prototype, { - } + isFog: true, - } else { + clone: function () { - for ( var i = 0, l = positions.length / 3; i < l; i ++ ) { + return new Fog( this.color, this.near, this.far ); - position.fromArray( positions, i * 3 ); + }, - testPoint( position, i ); + toJSON: function ( /* meta */ ) { - } + return { + type: 'Fog', + color: this.color.getHex(), + near: this.near, + far: this.far + }; - } + } - } else { + } ); - var vertices = geometry.vertices; + function InterleavedBuffer( array, stride ) { - for ( var i = 0, l = vertices.length; i < l; i ++ ) { + this.array = array; + this.stride = stride; + this.count = array !== undefined ? array.length / stride : 0; - testPoint( vertices[ i ], i ); + this.usage = StaticDrawUsage; + this.updateRange = { offset: 0, count: - 1 }; - } + this.version = 0; - } + this.uuid = MathUtils.generateUUID(); - }; + } - }() ), + Object.defineProperty( InterleavedBuffer.prototype, 'needsUpdate', { - clone: function () { + set: function ( value ) { - return new this.constructor( this.geometry, this.material ).copy( this ); + if ( value === true ) { this.version ++; } } } ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + Object.assign( InterleavedBuffer.prototype, { - function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + isInterleavedBuffer: true, - Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + onUploadCallback: function () {}, - this.generateMipmaps = false; + setUsage: function ( value ) { - } + this.usage = value; - VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), { + return this; - constructor: VideoTexture, + }, - isVideoTexture: true, + copy: function ( source ) { - update: function () { + this.array = new source.array.constructor( source.array ); + this.count = source.count; + this.stride = source.stride; + this.usage = source.usage; - var video = this.image; + return this; - if ( video.readyState >= video.HAVE_CURRENT_DATA ) { + }, - this.needsUpdate = true; + copyAt: function ( index1, attribute, index2 ) { - } + index1 *= this.stride; + index2 *= attribute.stride; - } + for ( var i = 0, l = this.stride; i < l; i ++ ) { - } ); + this.array[ index1 + i ] = attribute.array[ index2 + i ]; - /** - * @author alteredq / http://alteredqualia.com/ - */ + } - function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { + return this; - Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + }, - this.image = { width: width, height: height }; - this.mipmaps = mipmaps; + set: function ( value, offset ) { - // no flipping for cube textures - // (also flipping doesn't work for compressed textures ) + if ( offset === undefined ) { offset = 0; } - this.flipY = false; + this.array.set( value, offset ); - // can't generate mipmaps for compressed textures - // mips must be embedded in DDS files + return this; - this.generateMipmaps = false; + }, - } + clone: function ( data ) { - CompressedTexture.prototype = Object.create( Texture.prototype ); - CompressedTexture.prototype.constructor = CompressedTexture; + if ( data.arrayBuffers === undefined ) { - CompressedTexture.prototype.isCompressedTexture = true; + data.arrayBuffers = {}; - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + if ( this.array.buffer._uuid === undefined ) { - Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + this.array.buffer._uuid = MathUtils.generateUUID(); - this.needsUpdate = true; + } - } + if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - CanvasTexture.prototype = Object.create( Texture.prototype ); - CanvasTexture.prototype.constructor = CanvasTexture; - CanvasTexture.prototype.isCanvasTexture = true; + data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; - /** - * @author Matt DesLauriers / @mattdesl - * @author atix / arthursilber.de - */ + } - function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { + var array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); - format = format !== undefined ? format : DepthFormat; + var ib = new InterleavedBuffer( array, this.stride ); + ib.setUsage( this.usage ); - if ( format !== DepthFormat && format !== DepthStencilFormat ) { + return ib; - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); + }, - } + onUpload: function ( callback ) { - if ( type === undefined && format === DepthFormat ) type = UnsignedShortType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; + this.onUploadCallback = callback; - Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + return this; - this.image = { width: width, height: height }; + }, - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + toJSON: function ( data ) { - this.flipY = false; - this.generateMipmaps = false; + if ( data.arrayBuffers === undefined ) { - } + data.arrayBuffers = {}; - DepthTexture.prototype = Object.create( Texture.prototype ); - DepthTexture.prototype.constructor = DepthTexture; - DepthTexture.prototype.isDepthTexture = true; + } - /** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + // generate UUID for array buffer if necessary - function WireframeGeometry( geometry ) { + if ( this.array.buffer._uuid === undefined ) { - BufferGeometry.call( this ); + this.array.buffer._uuid = MathUtils.generateUUID(); - this.type = 'WireframeGeometry'; + } - // buffer + if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { - var vertices = []; + data.arrayBuffers[ this.array.buffer._uuid ] = Array.prototype.slice.call( new Uint32Array( this.array.buffer ) ); - // helper variables + } - var i, j, l, o, ol; - var edge = [ 0, 0 ], edges = {}, e, edge1, edge2; - var key, keys = [ 'a', 'b', 'c' ]; - var vertex; + // - // different logic for Geometry and BufferGeometry + return { + uuid: this.uuid, + buffer: this.array.buffer._uuid, + type: this.array.constructor.name, + stride: this.stride + }; - if ( geometry && geometry.isGeometry ) { + } - // create a data structure that contains all edges without duplicates + } ); - var faces = geometry.faces; + var _vector$6 = new Vector3(); - for ( i = 0, l = faces.length; i < l; i ++ ) { + function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normalized ) { - var face = faces[ i ]; + this.name = ''; - for ( j = 0; j < 3; j ++ ) { + this.data = interleavedBuffer; + this.itemSize = itemSize; + this.offset = offset; - edge1 = face[ keys[ j ] ]; - edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; - edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates - edge[ 1 ] = Math.max( edge1, edge2 ); + this.normalized = normalized === true; - key = edge[ 0 ] + ',' + edge[ 1 ]; + } - if ( edges[ key ] === undefined ) { + Object.defineProperties( InterleavedBufferAttribute.prototype, { - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; + count: { - } + get: function () { - } + return this.data.count; } - // generate vertices - - for ( key in edges ) { + }, - e = edges[ key ]; + array: { - vertex = geometry.vertices[ e.index1 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); + get: function () { - vertex = geometry.vertices[ e.index2 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); + return this.data.array; } - } else if ( geometry && geometry.isBufferGeometry ) { + }, - var position, indices, groups; - var group, start, count; - var index1, index2; + needsUpdate: { - vertex = new Vector3(); + set: function ( value ) { - if ( geometry.index !== null ) { + this.data.needsUpdate = value; - // indexed BufferGeometry + } - position = geometry.attributes.position; - indices = geometry.index; - groups = geometry.groups; + } - if ( groups.length === 0 ) { + } ); - groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; + Object.assign( InterleavedBufferAttribute.prototype, { - } + isInterleavedBufferAttribute: true, - // create a data structure that contains all eges without duplicates + applyMatrix4: function ( m ) { - for ( o = 0, ol = groups.length; o < ol; ++ o ) { + for ( var i = 0, l = this.data.count; i < l; i ++ ) { - group = groups[ o ]; + _vector$6.x = this.getX( i ); + _vector$6.y = this.getY( i ); + _vector$6.z = this.getZ( i ); - start = group.start; - count = group.count; + _vector$6.applyMatrix4( m ); - for ( i = start, l = ( start + count ); i < l; i += 3 ) { + this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); - for ( j = 0; j < 3; j ++ ) { + } - edge1 = indices.getX( i + j ); - edge2 = indices.getX( i + ( j + 1 ) % 3 ); - edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates - edge[ 1 ] = Math.max( edge1, edge2 ); + return this; - key = edge[ 0 ] + ',' + edge[ 1 ]; + }, - if ( edges[ key ] === undefined ) { + setX: function ( index, x ) { - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; + this.data.array[ index * this.data.stride + this.offset ] = x; - } + return this; - } + }, - } + setY: function ( index, y ) { - } + this.data.array[ index * this.data.stride + this.offset + 1 ] = y; - // generate vertices + return this; - for ( key in edges ) { + }, - e = edges[ key ]; + setZ: function ( index, z ) { - vertex.fromBufferAttribute( position, e.index1 ); - vertices.push( vertex.x, vertex.y, vertex.z ); + this.data.array[ index * this.data.stride + this.offset + 2 ] = z; - vertex.fromBufferAttribute( position, e.index2 ); - vertices.push( vertex.x, vertex.y, vertex.z ); + return this; - } + }, - } else { + setW: function ( index, w ) { - // non-indexed BufferGeometry + this.data.array[ index * this.data.stride + this.offset + 3 ] = w; - position = geometry.attributes.position; + return this; - for ( i = 0, l = ( position.count / 3 ); i < l; i ++ ) { + }, - for ( j = 0; j < 3; j ++ ) { + getX: function ( index ) { - // 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) + return this.data.array[ index * this.data.stride + this.offset ]; - index1 = 3 * i + j; - vertex.fromBufferAttribute( position, index1 ); - vertices.push( vertex.x, vertex.y, vertex.z ); + }, - index2 = 3 * i + ( ( j + 1 ) % 3 ); - vertex.fromBufferAttribute( position, index2 ); - vertices.push( vertex.x, vertex.y, vertex.z ); + getY: function ( index ) { - } + return this.data.array[ index * this.data.stride + this.offset + 1 ]; - } + }, - } + getZ: function ( index ) { - } + return this.data.array[ index * this.data.stride + this.offset + 2 ]; - // build geometry + }, - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + getW: function ( index ) { - } + return this.data.array[ index * this.data.stride + this.offset + 3 ]; - WireframeGeometry.prototype = Object.create( BufferGeometry.prototype ); - WireframeGeometry.prototype.constructor = WireframeGeometry; + }, - /** - * @author zz85 / https://github.com/zz85 - * @author Mugen87 / https://github.com/Mugen87 - * - * Parametric Surfaces Geometry - * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 - */ + setXY: function ( index, x, y ) { - // ParametricGeometry + index = index * this.data.stride + this.offset; - function ParametricGeometry( func, slices, stacks ) { + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; - Geometry.call( this ); + return this; - this.type = 'ParametricGeometry'; + }, - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; + setXYZ: function ( index, x, y, z ) { - this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) ); - this.mergeVertices(); + 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; - ParametricGeometry.prototype = Object.create( Geometry.prototype ); - ParametricGeometry.prototype.constructor = ParametricGeometry; + return this; - // ParametricBufferGeometry + }, - function ParametricBufferGeometry( func, slices, stacks ) { + setXYZW: function ( index, x, y, z, w ) { - BufferGeometry.call( this ); + index = index * this.data.stride + this.offset; - this.type = 'ParametricBufferGeometry'; + this.data.array[ index + 0 ] = x; + this.data.array[ index + 1 ] = y; + this.data.array[ index + 2 ] = z; + this.data.array[ index + 3 ] = w; - this.parameters = { - func: func, - slices: slices, - stacks: stacks - }; + return this; - // buffers + }, - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + clone: function ( data ) { - var EPS = 0.00001; + if ( data === undefined ) { - var normal = new Vector3(); + console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interlaved buffer attribute will deinterleave buffer data.' ); - var p0 = new Vector3(), p1 = new Vector3(); - var pu = new Vector3(), pv = new Vector3(); + var array = []; - var i, j; + for ( var i = 0; i < this.count; i ++ ) { - if ( func.length < 3 ) { + var index = i * this.data.stride + this.offset; - console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' ); + for ( var j = 0; j < this.itemSize; j ++ ) { - } + array.push( this.data.array[ index + j ] ); - // generate vertices, normals and uvs + } - var sliceCount = slices + 1; + } - for ( i = 0; i <= stacks; i ++ ) { + return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); - var v = i / stacks; + } else { - for ( j = 0; j <= slices; j ++ ) { + if ( data.interleavedBuffers === undefined ) { - var u = j / slices; + data.interleavedBuffers = {}; - // vertex + } - func( u, v, p0 ); - vertices.push( p0.x, p0.y, p0.z ); + if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - // normal + data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); - // approximate tangent vectors via finite differences + } - if ( u - EPS >= 0 ) { + return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); - func( u - EPS, v, p1 ); - pu.subVectors( p0, p1 ); + } - } else { + }, - func( u + EPS, v, p1 ); - pu.subVectors( p1, p0 ); + toJSON: function ( data ) { - } + if ( data === undefined ) { - if ( v - EPS >= 0 ) { + console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interlaved buffer attribute will deinterleave buffer data.' ); - func( u, v - EPS, p1 ); - pv.subVectors( p0, p1 ); + var array = []; - } else { + for ( var i = 0; i < this.count; i ++ ) { - func( u, v + EPS, p1 ); - pv.subVectors( p1, p0 ); + var index = i * this.data.stride + this.offset; - } + for ( var j = 0; j < this.itemSize; j ++ ) { - // cross product of tangent vectors returns surface normal + array.push( this.data.array[ index + j ] ); - normal.crossVectors( pu, pv ).normalize(); - normals.push( normal.x, normal.y, normal.z ); + } - // uv + } - uvs.push( u, v ); + // 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 { - // generate indices + // save as true interlaved attribtue - for ( i = 0; i < stacks; i ++ ) { + if ( data.interleavedBuffers === undefined ) { - for ( j = 0; j < slices; j ++ ) { + data.interleavedBuffers = {}; - var a = i * sliceCount + j; - var b = i * sliceCount + j + 1; - var c = ( i + 1 ) * sliceCount + j + 1; - var d = ( i + 1 ) * sliceCount + j; + } - // faces one and two + if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { - indices.push( a, b, d ); - indices.push( b, c, d ); + 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 + }; } } - // build geometry + } ); - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + /** + * parameters = { + * color: , + * map: new THREE.Texture( ), + * alphaMap: new THREE.Texture( ), + * rotation: , + * sizeAttenuation: + * } + */ - } + function SpriteMaterial( parameters ) { - ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry; + Material.call( this ); - /** - * @author clockworkgeek / https://github.com/clockworkgeek - * @author timothypratley / https://github.com/timothypratley - * @author WestLangley / http://github.com/WestLangley - * @author Mugen87 / https://github.com/Mugen87 - */ + this.type = 'SpriteMaterial'; - // PolyhedronGeometry + this.color = new Color( 0xffffff ); - function PolyhedronGeometry( vertices, indices, radius, detail ) { + this.map = null; - Geometry.call( this ); + this.alphaMap = null; - this.type = 'PolyhedronGeometry'; + this.rotation = 0; - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; + this.sizeAttenuation = true; - this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) ); - this.mergeVertices(); + this.transparent = true; + + this.setValues( parameters ); } - PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); - PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; + SpriteMaterial.prototype = Object.create( Material.prototype ); + SpriteMaterial.prototype.constructor = SpriteMaterial; + SpriteMaterial.prototype.isSpriteMaterial = true; - // PolyhedronBufferGeometry + SpriteMaterial.prototype.copy = function ( source ) { - function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { + Material.prototype.copy.call( this, source ); - BufferGeometry.call( this ); + this.color.copy( source.color ); - this.type = 'PolyhedronBufferGeometry'; + this.map = source.map; - this.parameters = { - vertices: vertices, - indices: indices, - radius: radius, - detail: detail - }; + this.alphaMap = source.alphaMap; - radius = radius || 1; - detail = detail || 0; + this.rotation = source.rotation; - // default buffer data + this.sizeAttenuation = source.sizeAttenuation; - var vertexBuffer = []; - var uvBuffer = []; + return this; - // the subdivision creates the vertex buffer data + }; - subdivide( detail ); + var _geometry; - // all vertices should lie on a conceptual sphere with a given radius + var _intersectPoint = new Vector3(); + var _worldScale = new Vector3(); + var _mvPosition = new Vector3(); - appplyRadius( radius ); + var _alignedPosition = new Vector2(); + var _rotatedPosition = new Vector2(); + var _viewWorldMatrix = new Matrix4(); - // finally, create the uv data + var _vA$1 = new Vector3(); + var _vB$1 = new Vector3(); + var _vC$1 = new Vector3(); - generateUVs(); + var _uvA$1 = new Vector2(); + var _uvB$1 = new Vector2(); + var _uvC$1 = new Vector2(); - // build non-indexed geometry + function Sprite( material ) { - this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); + Object3D.call( this ); - if ( detail === 0 ) { + this.type = 'Sprite'; - this.computeVertexNormals(); // flat normals + if ( _geometry === undefined ) { - } else { + _geometry = new BufferGeometry(); - this.normalizeNormals(); // smooth normals + var 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 + ] ); + + var 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 ) ); } - // helper functions + this.geometry = _geometry; + this.material = ( material !== undefined ) ? material : new SpriteMaterial(); - function subdivide( detail ) { + this.center = new Vector2( 0.5, 0.5 ); - var a = new Vector3(); - var b = new Vector3(); - var c = new Vector3(); + } - // iterate over all faces and apply a subdivison with the given detail value + Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), { - for ( var i = 0; i < indices.length; i += 3 ) { + constructor: Sprite, - // get the vertices of the face + isSprite: true, - getVertexByIndex( indices[ i + 0 ], a ); - getVertexByIndex( indices[ i + 1 ], b ); - getVertexByIndex( indices[ i + 2 ], c ); + raycast: function ( raycaster, intersects ) { - // perform subdivision + if ( raycaster.camera === null ) { - subdivideFace( a, b, c, detail ); + console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); } - } + _worldScale.setFromMatrixScale( this.matrixWorld ); - function subdivideFace( a, b, c, detail ) { + _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); + this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); - var cols = Math.pow( 2, detail ); + _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); - // we use this multidimensional array as a data structure for creating the subdivision + if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { - var v = []; + _worldScale.multiplyScalar( - _mvPosition.z ); - var i, j; + } - // construct all of the vertices for this subdivision + var rotation = this.material.rotation; + var sin, cos; - for ( i = 0; i <= cols; i ++ ) { + if ( rotation !== 0 ) { - v[ i ] = []; + cos = Math.cos( rotation ); + sin = Math.sin( rotation ); - var aj = a.clone().lerp( c, i / cols ); - var bj = b.clone().lerp( c, i / cols ); + } - var rows = cols - i; + var center = this.center; - for ( j = 0; j <= rows; j ++ ) { + transformVertex( _vA$1.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + transformVertex( _vB$1.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + transformVertex( _vC$1.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); - if ( j === 0 && i === cols ) { + _uvA$1.set( 0, 0 ); + _uvB$1.set( 1, 0 ); + _uvC$1.set( 1, 1 ); - v[ i ][ j ] = aj; + // check first triangle + var intersect = raycaster.ray.intersectTriangle( _vA$1, _vB$1, _vC$1, false, _intersectPoint ); - } else { + if ( intersect === null ) { - v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); + // check second triangle + transformVertex( _vB$1.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); + _uvB$1.set( 0, 1 ); - } + intersect = raycaster.ray.intersectTriangle( _vA$1, _vC$1, _vB$1, false, _intersectPoint ); + if ( intersect === null ) { + + return; } } - // construct all of the faces + var distance = raycaster.ray.origin.distanceTo( _intersectPoint ); - for ( i = 0; i < cols; i ++ ) { + if ( distance < raycaster.near || distance > raycaster.far ) { return; } - for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { + intersects.push( { - var k = Math.floor( j / 2 ); + distance: distance, + point: _intersectPoint.clone(), + uv: Triangle.getUV( _intersectPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ), + face: null, + object: this - if ( j % 2 === 0 ) { + } ); - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); - pushVertex( v[ i ][ k ] ); + }, - } else { + copy: function ( source ) { - pushVertex( v[ i ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k + 1 ] ); - pushVertex( v[ i + 1 ][ k ] ); + Object3D.prototype.copy.call( this, source ); - } + if ( source.center !== undefined ) { this.center.copy( source.center ); } - } + this.material = source.material; - } + return this; } - function appplyRadius( radius ) { - - var vertex = new Vector3(); + } ); - // iterate over the entire buffer and apply the radius to each vertex + function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { - for ( var i = 0; i < vertexBuffer.length; i += 3 ) { + // compute position in camera space + _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; + // to check if rotation is not zero + if ( sin !== undefined ) { - vertex.normalize().multiplyScalar( radius ); + _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); + _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); - vertexBuffer[ i + 0 ] = vertex.x; - vertexBuffer[ i + 1 ] = vertex.y; - vertexBuffer[ i + 2 ] = vertex.z; + } else { - } + _rotatedPosition.copy( _alignedPosition ); } - function generateUVs() { - var vertex = new Vector3(); + vertexPosition.copy( mvPosition ); + vertexPosition.x += _rotatedPosition.x; + vertexPosition.y += _rotatedPosition.y; - for ( var i = 0; i < vertexBuffer.length; i += 3 ) { + // transform to world space + vertexPosition.applyMatrix4( _viewWorldMatrix ); - vertex.x = vertexBuffer[ i + 0 ]; - vertex.y = vertexBuffer[ i + 1 ]; - vertex.z = vertexBuffer[ i + 2 ]; + } - var u = azimuth( vertex ) / 2 / Math.PI + 0.5; - var v = inclination( vertex ) / Math.PI + 0.5; - uvBuffer.push( u, 1 - v ); + var _v1$4 = new Vector3(); + var _v2$2 = new Vector3(); - } + function LOD() { - correctUVs(); + Object3D.call( this ); - correctSeam(); + this._currentLevel = 0; - } + this.type = 'LOD'; - function correctSeam() { + Object.defineProperties( this, { + levels: { + enumerable: true, + value: [] + } + } ); - // handle case when face straddles the seam, see #3269 + this.autoUpdate = true; - for ( var i = 0; i < uvBuffer.length; i += 6 ) { + } - // uv data of a single face + LOD.prototype = Object.assign( Object.create( Object3D.prototype ), { - var x0 = uvBuffer[ i + 0 ]; - var x1 = uvBuffer[ i + 2 ]; - var x2 = uvBuffer[ i + 4 ]; + constructor: LOD, - var max = Math.max( x0, x1, x2 ); - var min = Math.min( x0, x1, x2 ); + isLOD: true, - // 0.9 is somewhat arbitrary + copy: function ( source ) { - if ( max > 0.9 && min < 0.1 ) { + Object3D.prototype.copy.call( this, source, false ); - if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; - if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; - if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; + var levels = source.levels; - } + for ( var i = 0, l = levels.length; i < l; i ++ ) { - } + var level = levels[ i ]; - } + this.addLevel( level.object.clone(), level.distance ); - function pushVertex( vertex ) { + } - vertexBuffer.push( vertex.x, vertex.y, vertex.z ); + this.autoUpdate = source.autoUpdate; - } + return this; - function getVertexByIndex( index, vertex ) { + }, - var stride = index * 3; + addLevel: function ( object, distance ) { - vertex.x = vertices[ stride + 0 ]; - vertex.y = vertices[ stride + 1 ]; - vertex.z = vertices[ stride + 2 ]; + if ( distance === undefined ) { distance = 0; } - } + distance = Math.abs( distance ); - function correctUVs() { + var levels = this.levels; - var a = new Vector3(); - var b = new Vector3(); - var c = new Vector3(); + var l; - var centroid = new Vector3(); + for ( l = 0; l < levels.length; l ++ ) { - var uvA = new Vector2(); - var uvB = new Vector2(); - var uvC = new Vector2(); + if ( distance < levels[ l ].distance ) { - for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { + break; - 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 ); + levels.splice( l, 0, { distance: distance, object: object } ); - var azi = azimuth( centroid ); + this.add( object ); - correctUV( uvA, j + 0, a, azi ); - correctUV( uvB, j + 2, b, azi ); - correctUV( uvC, j + 4, c, azi ); + return this; - } + }, - } + getCurrentLevel: function () { - function correctUV( uv, stride, vector, azimuth ) { + return this._currentLevel; - if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { + }, - uvBuffer[ stride ] = uv.x - 1; + getObjectForDistance: function ( distance ) { - } + var levels = this.levels; - if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { + if ( levels.length > 0 ) { - uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; + var i, l; - } + for ( i = 1, l = levels.length; i < l; i ++ ) { - } + if ( distance < levels[ i ].distance ) { - // Angle around the Y axis, counter-clockwise when looking from above. + break; - function azimuth( vector ) { + } - return Math.atan2( vector.z, - vector.x ); + } - } + return levels[ i - 1 ].object; + } - // Angle above the XZ plane. + return null; - function inclination( vector ) { + }, - return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); + raycast: function ( raycaster, intersects ) { - } + var levels = this.levels; - } + if ( levels.length > 0 ) { - PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry; + _v1$4.setFromMatrixPosition( this.matrixWorld ); - /** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 - */ + var distance = raycaster.ray.origin.distanceTo( _v1$4 ); - // TetrahedronGeometry + this.getObjectForDistance( distance ).raycast( raycaster, intersects ); - function TetrahedronGeometry( radius, detail ) { + } - Geometry.call( this ); + }, - this.type = 'TetrahedronGeometry'; + update: function ( camera ) { - this.parameters = { - radius: radius, - detail: detail - }; + var levels = this.levels; - this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); + if ( levels.length > 1 ) { - } + _v1$4.setFromMatrixPosition( camera.matrixWorld ); + _v2$2.setFromMatrixPosition( this.matrixWorld ); - TetrahedronGeometry.prototype = Object.create( Geometry.prototype ); - TetrahedronGeometry.prototype.constructor = TetrahedronGeometry; + var distance = _v1$4.distanceTo( _v2$2 ) / camera.zoom; - // TetrahedronBufferGeometry + levels[ 0 ].object.visible = true; - function TetrahedronBufferGeometry( radius, detail ) { + var i, l; - var vertices = [ - 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 - ]; + for ( i = 1, l = levels.length; i < l; i ++ ) { - var indices = [ - 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 - ]; + if ( distance >= levels[ i ].distance ) { - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + levels[ i - 1 ].object.visible = false; + levels[ i ].object.visible = true; - this.type = 'TetrahedronBufferGeometry'; + } else { - this.parameters = { - radius: radius, - detail: detail - }; + break; - } + } - TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); - TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry; + } - /** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 - */ + this._currentLevel = i - 1; - // OctahedronGeometry + for ( ; i < l; i ++ ) { - function OctahedronGeometry( radius, detail ) { + levels[ i ].object.visible = false; - Geometry.call( this ); + } - this.type = 'OctahedronGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + }, - this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); + toJSON: function ( meta ) { - } + var data = Object3D.prototype.toJSON.call( this, meta ); - OctahedronGeometry.prototype = Object.create( Geometry.prototype ); - OctahedronGeometry.prototype.constructor = OctahedronGeometry; + if ( this.autoUpdate === false ) { data.object.autoUpdate = false; } - // OctahedronBufferGeometry + data.object.levels = []; - function OctahedronBufferGeometry( radius, detail ) { + var levels = this.levels; - var vertices = [ - 1, 0, 0, - 1, 0, 0, 0, 1, 0, - 0, - 1, 0, 0, 0, 1, 0, 0, - 1 - ]; + for ( var i = 0, l = levels.length; i < l; i ++ ) { - var 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 - ]; + var level = levels[ i ]; - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + data.object.levels.push( { + object: level.object.uuid, + distance: level.distance + } ); - this.type = 'OctahedronBufferGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + return data; - } + } - OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); - OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry; + } ); - /** - * @author timothypratley / https://github.com/timothypratley - * @author Mugen87 / https://github.com/Mugen87 - */ + function SkinnedMesh( geometry, material ) { - // IcosahedronGeometry + if ( geometry && geometry.isGeometry ) { - function IcosahedronGeometry( radius, detail ) { + console.error( 'THREE.SkinnedMesh no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' ); - Geometry.call( this ); + } - this.type = 'IcosahedronGeometry'; + Mesh.call( this, geometry, material ); - this.parameters = { - radius: radius, - detail: detail - }; + this.type = 'SkinnedMesh'; - this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); + this.bindMode = 'attached'; + this.bindMatrix = new Matrix4(); + this.bindMatrixInverse = new Matrix4(); } - IcosahedronGeometry.prototype = Object.create( Geometry.prototype ); - IcosahedronGeometry.prototype.constructor = IcosahedronGeometry; + SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { - // IcosahedronBufferGeometry + constructor: SkinnedMesh, - function IcosahedronBufferGeometry( radius, detail ) { + isSkinnedMesh: true, - var t = ( 1 + Math.sqrt( 5 ) ) / 2; + copy: function ( source ) { - var vertices = [ - - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, - 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, - t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 - ]; + Mesh.prototype.copy.call( this, source ); - var 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 - ]; + this.bindMode = source.bindMode; + this.bindMatrix.copy( source.bindMatrix ); + this.bindMatrixInverse.copy( source.bindMatrixInverse ); - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + this.skeleton = source.skeleton; - this.type = 'IcosahedronBufferGeometry'; + return this; - this.parameters = { - radius: radius, - detail: detail - }; + }, - } + bind: function ( skeleton, bindMatrix ) { - IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); - IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry; + this.skeleton = skeleton; - /** - * @author Abe Pazos / https://hamoid.com - * @author Mugen87 / https://github.com/Mugen87 - */ + if ( bindMatrix === undefined ) { - // DodecahedronGeometry + this.updateMatrixWorld( true ); - function DodecahedronGeometry( radius, detail ) { + this.skeleton.calculateInverses(); - Geometry.call( this ); + bindMatrix = this.matrixWorld; - this.type = 'DodecahedronGeometry'; + } - this.parameters = { - radius: radius, - detail: detail - }; + this.bindMatrix.copy( bindMatrix ); + this.bindMatrixInverse.getInverse( bindMatrix ); - this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) ); - this.mergeVertices(); + }, - } + pose: function () { - DodecahedronGeometry.prototype = Object.create( Geometry.prototype ); - DodecahedronGeometry.prototype.constructor = DodecahedronGeometry; + this.skeleton.pose(); - // DodecahedronBufferGeometry + }, - function DodecahedronBufferGeometry( radius, detail ) { + normalizeSkinWeights: function () { - var t = ( 1 + Math.sqrt( 5 ) ) / 2; - var r = 1 / t; + var vector = new Vector4(); - var vertices = [ + var skinWeight = this.geometry.attributes.skinWeight; - // (±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, + for ( var i = 0, l = skinWeight.count; i < l; i ++ ) { - // (0, ±1/φ, ±φ) - 0, - r, - t, 0, - r, t, - 0, r, - t, 0, r, t, + vector.x = skinWeight.getX( i ); + vector.y = skinWeight.getY( i ); + vector.z = skinWeight.getZ( i ); + vector.w = skinWeight.getW( i ); - // (±1/φ, ±φ, 0) - - r, - t, 0, - r, t, 0, - r, - t, 0, r, t, 0, + var scale = 1.0 / vector.manhattanLength(); - // (±φ, 0, ±1/φ) - - t, 0, - r, t, 0, - r, - - t, 0, r, t, 0, r - ]; + if ( scale !== Infinity ) { - var 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 - ]; + vector.multiplyScalar( scale ); - PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); + } else { - this.type = 'DodecahedronBufferGeometry'; + vector.set( 1, 0, 0, 0 ); // do something reasonable - this.parameters = { - radius: radius, - detail: detail - }; + } - } + skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); - DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); - DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry; + } - /** - * @author oosmoxiecode / https://github.com/oosmoxiecode - * @author WestLangley / https://github.com/WestLangley - * @author zz85 / https://github.com/zz85 - * @author miningold / https://github.com/miningold - * @author jonobr1 / https://github.com/jonobr1 - * @author Mugen87 / https://github.com/Mugen87 - * - */ + }, - // TubeGeometry + updateMatrixWorld: function ( force ) { - function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) { + Mesh.prototype.updateMatrixWorld.call( this, force ); - Geometry.call( this ); + if ( this.bindMode === 'attached' ) { - this.type = 'TubeGeometry'; + this.bindMatrixInverse.getInverse( this.matrixWorld ); - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; + } else if ( this.bindMode === 'detached' ) { - if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' ); + this.bindMatrixInverse.getInverse( this.bindMatrix ); - var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ); + } else { - // expose internals + console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); - this.tangents = bufferGeometry.tangents; - this.normals = bufferGeometry.normals; - this.binormals = bufferGeometry.binormals; + } - // create geometry + }, - this.fromBufferGeometry( bufferGeometry ); - this.mergeVertices(); + boneTransform: ( function () { - } + var basePosition = new Vector3(); - TubeGeometry.prototype = Object.create( Geometry.prototype ); - TubeGeometry.prototype.constructor = TubeGeometry; + var skinIndex = new Vector4(); + var skinWeight = new Vector4(); - // TubeBufferGeometry + var vector = new Vector3(); + var matrix = new Matrix4(); - function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) { + return function ( index, target ) { - BufferGeometry.call( this ); + var skeleton = this.skeleton; + var geometry = this.geometry; - this.type = 'TubeBufferGeometry'; + skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); + skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); - this.parameters = { - path: path, - tubularSegments: tubularSegments, - radius: radius, - radialSegments: radialSegments, - closed: closed - }; + basePosition.fromBufferAttribute( geometry.attributes.position, index ).applyMatrix4( this.bindMatrix ); - tubularSegments = tubularSegments || 64; - radius = radius || 1; - radialSegments = radialSegments || 8; - closed = closed || false; + target.set( 0, 0, 0 ); - var frames = path.computeFrenetFrames( tubularSegments, closed ); + for ( var i = 0; i < 4; i ++ ) { - // expose internals + var weight = skinWeight.getComponent( i ); - this.tangents = frames.tangents; - this.normals = frames.normals; - this.binormals = frames.binormals; + if ( weight !== 0 ) { - // helper variables + var boneIndex = skinIndex.getComponent( i ); - var vertex = new Vector3(); - var normal = new Vector3(); - var uv = new Vector2(); - var P = new Vector3(); + matrix.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); - var i, j; + target.addScaledVector( vector.copy( basePosition ).applyMatrix4( matrix ), weight ); - // buffer + } - var vertices = []; - var normals = []; - var uvs = []; - var indices = []; + } - // create buffer data + return target.applyMatrix4( this.bindMatrixInverse ); - generateBufferData(); + }; - // build geometry + }() ) - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + } ); - // functions + var _offsetMatrix = new Matrix4(); + var _identityMatrix = new Matrix4(); - function generateBufferData() { + function Skeleton( bones, boneInverses ) { - for ( i = 0; i < tubularSegments; i ++ ) { + // copy the bone array - generateSegment( i ); + bones = bones || []; - } + this.bones = bones.slice( 0 ); + this.boneMatrices = new Float32Array( this.bones.length * 16 ); - // 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) + this.frame = - 1; - generateSegment( ( closed === false ) ? tubularSegments : 0 ); + // use the supplied bone inverses or calculate the inverses - // uvs are generated in a separate function. - // this makes it easy compute correct values for closed geometries + if ( boneInverses === undefined ) { - generateUVs(); + this.calculateInverses(); - // finally create faces + } else { - generateIndices(); + if ( this.bones.length === boneInverses.length ) { - } + this.boneInverses = boneInverses.slice( 0 ); - function generateSegment( i ) { + } else { - // we use getPointAt to sample evenly distributed points from the given path + console.warn( 'THREE.Skeleton boneInverses is the wrong length.' ); - P = path.getPointAt( i / tubularSegments, P ); + this.boneInverses = []; - // retrieve corresponding normal and binormal + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { - var N = frames.normals[ i ]; - var B = frames.binormals[ i ]; + this.boneInverses.push( new Matrix4() ); - // generate normals and vertices for the current segment + } - for ( j = 0; j <= radialSegments; j ++ ) { + } - var v = j / radialSegments * Math.PI * 2; + } - var sin = Math.sin( v ); - var cos = - Math.cos( v ); + } - // normal + Object.assign( Skeleton.prototype, { - 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(); + calculateInverses: function () { - normals.push( normal.x, normal.y, normal.z ); + this.boneInverses = []; - // vertex + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { - vertex.x = P.x + radius * normal.x; - vertex.y = P.y + radius * normal.y; - vertex.z = P.z + radius * normal.z; + var inverse = new Matrix4(); - vertices.push( vertex.x, vertex.y, vertex.z ); + if ( this.bones[ i ] ) { + + inverse.getInverse( this.bones[ i ].matrixWorld ); + + } + + this.boneInverses.push( inverse ); } - } + }, - function generateIndices() { + pose: function () { - for ( j = 1; j <= tubularSegments; j ++ ) { + // recover the bind-time world matrices - for ( i = 1; i <= radialSegments; i ++ ) { + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { - var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - var b = ( radialSegments + 1 ) * j + ( i - 1 ); - var c = ( radialSegments + 1 ) * j + i; - var d = ( radialSegments + 1 ) * ( j - 1 ) + i; + var bone = this.bones[ i ]; - // faces + if ( bone ) { - indices.push( a, b, d ); - indices.push( b, c, d ); + bone.matrixWorld.getInverse( this.boneInverses[ i ] ); } } - } + // compute the local matrices, positions, rotations and scales - function generateUVs() { + for ( var i$1 = 0, il$1 = this.bones.length; i$1 < il$1; i$1 ++ ) { - for ( i = 0; i <= tubularSegments; i ++ ) { + var bone$1 = this.bones[ i$1 ]; - for ( j = 0; j <= radialSegments; j ++ ) { + if ( bone$1 ) { - uv.x = i / tubularSegments; - uv.y = j / radialSegments; + if ( bone$1.parent && bone$1.parent.isBone ) { - uvs.push( uv.x, uv.y ); + bone$1.matrix.getInverse( bone$1.parent.matrixWorld ); + bone$1.matrix.multiply( bone$1.matrixWorld ); - } + } else { - } + bone$1.matrix.copy( bone$1.matrixWorld ); - } + } - } + bone$1.matrix.decompose( bone$1.position, bone$1.quaternion, bone$1.scale ); - TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - TubeBufferGeometry.prototype.constructor = TubeBufferGeometry; + } - /** - * @author oosmoxiecode - * @author Mugen87 / https://github.com/Mugen87 - * - * based on http://www.blackpawn.com/texts/pqtorus/ - */ + } - // TorusKnotGeometry + }, - function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) { + update: function () { - Geometry.call( this ); + var bones = this.bones; + var boneInverses = this.boneInverses; + var boneMatrices = this.boneMatrices; + var boneTexture = this.boneTexture; - this.type = 'TorusKnotGeometry'; + // flatten bone matrices to array - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; + for ( var i = 0, il = bones.length; i < il; i ++ ) { - if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' ); + // compute the offset between the current and the original transform - this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) ); - this.mergeVertices(); + var matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix; - } + _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); + _offsetMatrix.toArray( boneMatrices, i * 16 ); - TorusKnotGeometry.prototype = Object.create( Geometry.prototype ); - TorusKnotGeometry.prototype.constructor = TorusKnotGeometry; + } - // TorusKnotBufferGeometry + if ( boneTexture !== undefined ) { - function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) { + boneTexture.needsUpdate = true; - BufferGeometry.call( this ); + } - this.type = 'TorusKnotBufferGeometry'; + }, - this.parameters = { - radius: radius, - tube: tube, - tubularSegments: tubularSegments, - radialSegments: radialSegments, - p: p, - q: q - }; + clone: function () { - radius = radius || 1; - tube = tube || 0.4; - tubularSegments = Math.floor( tubularSegments ) || 64; - radialSegments = Math.floor( radialSegments ) || 8; - p = p || 2; - q = q || 3; + return new Skeleton( this.bones, this.boneInverses ); - // buffers + }, - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + getBoneByName: function ( name ) { - // helper variables + for ( var i = 0, il = this.bones.length; i < il; i ++ ) { - var i, j; + var bone = this.bones[ i ]; - var vertex = new Vector3(); - var normal = new Vector3(); + if ( bone.name === name ) { - var P1 = new Vector3(); - var P2 = new Vector3(); + return bone; - var B = new Vector3(); - var T = new Vector3(); - var N = new Vector3(); + } - // generate vertices, normals and uvs + } - for ( i = 0; i <= tubularSegments; ++ i ) { + return undefined; - // the radian "u" is used to calculate the position on the torus curve of the current tubular segement + }, - var u = i / tubularSegments * p * Math.PI * 2; + dispose: function ( ) { - // 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 + if ( this.boneTexture ) { - calculatePositionOnCurve( u, p, q, radius, P1 ); - calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); + this.boneTexture.dispose(); - // calculate orthonormal basis + this.boneTexture = undefined; - 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 ( j = 0; j <= radialSegments; ++ j ) { + function Bone() { - // 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. + Object3D.call( this ); - var v = j / radialSegments * Math.PI * 2; - var cx = - tube * Math.cos( v ); - var cy = tube * Math.sin( v ); + this.type = 'Bone'; - // 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 ); + Bone.prototype = Object.assign( Object.create( Object3D.prototype ), { - vertices.push( vertex.x, vertex.y, vertex.z ); + constructor: Bone, - // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) + isBone: true - normal.subVectors( vertex, P1 ).normalize(); + } ); - normals.push( normal.x, normal.y, normal.z ); + var _instanceLocalMatrix = new Matrix4(); + var _instanceWorldMatrix = new Matrix4(); - // uv + var _instanceIntersects = []; - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); + var _mesh = new Mesh(); - } + function InstancedMesh( geometry, material, count ) { - } + Mesh.call( this, geometry, material ); - // generate indices + this.instanceMatrix = new BufferAttribute( new Float32Array( count * 16 ), 16 ); - for ( j = 1; j <= tubularSegments; j ++ ) { + this.count = count; - for ( i = 1; i <= radialSegments; i ++ ) { + this.frustumCulled = false; - // indices + } - var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); - var b = ( radialSegments + 1 ) * j + ( i - 1 ); - var c = ( radialSegments + 1 ) * j + i; - var d = ( radialSegments + 1 ) * ( j - 1 ) + i; + InstancedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), { - // faces + constructor: InstancedMesh, - indices.push( a, b, d ); - indices.push( b, c, d ); + isInstancedMesh: true, - } + copy: function ( source ) { - } + Mesh.prototype.copy.call( this, source ); - // build geometry + this.instanceMatrix.copy( source.instanceMatrix ); + this.count = source.count; - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + return this; - // this function calculates the current position on the torus curve + }, - function calculatePositionOnCurve( u, p, q, radius, position ) { + getMatrixAt: function ( index, matrix ) { - var cu = Math.cos( u ); - var su = Math.sin( u ); - var quOverP = q / p * u; - var cs = Math.cos( quOverP ); + matrix.fromArray( this.instanceMatrix.array, index * 16 ); - position.x = radius * ( 2 + cs ) * 0.5 * cu; - position.y = radius * ( 2 + cs ) * su * 0.5; - position.z = radius * Math.sin( quOverP ) * 0.5; + }, - } + raycast: function ( raycaster, intersects ) { - } + var matrixWorld = this.matrixWorld; + var raycastTimes = this.count; - TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry; + _mesh.geometry = this.geometry; + _mesh.material = this.material; - /** - * @author oosmoxiecode - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + if ( _mesh.material === undefined ) { return; } - // TorusGeometry + for ( var instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { - function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) { + // calculate the world matrix for each instance - Geometry.call( this ); + this.getMatrixAt( instanceId, _instanceLocalMatrix ); - this.type = 'TorusGeometry'; + _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; + // the mesh represents this single instance - this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) ); - this.mergeVertices(); + _mesh.matrixWorld = _instanceWorldMatrix; - } + _mesh.raycast( raycaster, _instanceIntersects ); - TorusGeometry.prototype = Object.create( Geometry.prototype ); - TorusGeometry.prototype.constructor = TorusGeometry; + // process the result of raycast - // TorusBufferGeometry + for ( var i = 0, l = _instanceIntersects.length; i < l; i ++ ) { - function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) { + var intersect = _instanceIntersects[ i ]; + intersect.instanceId = instanceId; + intersect.object = this; + intersects.push( intersect ); - BufferGeometry.call( this ); + } - this.type = 'TorusBufferGeometry'; + _instanceIntersects.length = 0; - this.parameters = { - radius: radius, - tube: tube, - radialSegments: radialSegments, - tubularSegments: tubularSegments, - arc: arc - }; + } - radius = radius || 1; - tube = tube || 0.4; - radialSegments = Math.floor( radialSegments ) || 8; - tubularSegments = Math.floor( tubularSegments ) || 6; - arc = arc || Math.PI * 2; + }, - // buffers + setMatrixAt: function ( index, matrix ) { - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + matrix.toArray( this.instanceMatrix.array, index * 16 ); - // helper variables + }, - var center = new Vector3(); - var vertex = new Vector3(); - var normal = new Vector3(); + updateMorphTargets: function () { - var j, i; + } - // generate vertices, normals and uvs + } ); - for ( j = 0; j <= radialSegments; j ++ ) { + /** + * parameters = { + * color: , + * opacity: , + * + * linewidth: , + * linecap: "round", + * linejoin: "round" + * } + */ - for ( i = 0; i <= tubularSegments; i ++ ) { + function LineBasicMaterial( parameters ) { - var u = i / tubularSegments * arc; - var v = j / radialSegments * Math.PI * 2; + Material.call( this ); - // vertex + this.type = 'LineBasicMaterial'; - 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 ); + this.color = new Color( 0xffffff ); - vertices.push( vertex.x, vertex.y, vertex.z ); + this.linewidth = 1; + this.linecap = 'round'; + this.linejoin = 'round'; - // normal + this.morphTargets = false; - center.x = radius * Math.cos( u ); - center.y = radius * Math.sin( u ); - normal.subVectors( vertex, center ).normalize(); + this.setValues( parameters ); - normals.push( normal.x, normal.y, normal.z ); + } - // uv + LineBasicMaterial.prototype = Object.create( Material.prototype ); + LineBasicMaterial.prototype.constructor = LineBasicMaterial; - uvs.push( i / tubularSegments ); - uvs.push( j / radialSegments ); + LineBasicMaterial.prototype.isLineBasicMaterial = true; - } + LineBasicMaterial.prototype.copy = function ( source ) { - } + Material.prototype.copy.call( this, source ); - // generate indices + this.color.copy( source.color ); - for ( j = 1; j <= radialSegments; j ++ ) { + this.linewidth = source.linewidth; + this.linecap = source.linecap; + this.linejoin = source.linejoin; - for ( i = 1; i <= tubularSegments; i ++ ) { + this.morphTargets = source.morphTargets; - // indices + return this; - var a = ( tubularSegments + 1 ) * j + i - 1; - var b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; - var c = ( tubularSegments + 1 ) * ( j - 1 ) + i; - var d = ( tubularSegments + 1 ) * j + i; + }; - // faces + var _start = new Vector3(); + var _end = new Vector3(); + var _inverseMatrix$1 = new Matrix4(); + var _ray$1 = new Ray(); + var _sphere$2 = new Sphere(); - indices.push( a, b, d ); - indices.push( b, c, d ); + function Line( geometry, material, mode ) { - } + if ( mode === 1 ) { + + console.error( 'THREE.Line: parameter THREE.LinePieces no longer supported. Use THREE.LineSegments instead.' ); } - // build geometry + Object3D.call( this ); - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + this.type = 'Line'; - } + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new LineBasicMaterial(); - TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - TorusBufferGeometry.prototype.constructor = TorusBufferGeometry; + this.updateMorphTargets(); - /** - * @author Mugen87 / https://github.com/Mugen87 - * Port from https://github.com/mapbox/earcut (v2.1.2) - */ + } - var Earcut = { + Line.prototype = Object.assign( Object.create( Object3D.prototype ), { - triangulate: function ( data, holeIndices, dim ) { + constructor: Line, - dim = dim || 2; + isLine: true, - var hasHoles = holeIndices && holeIndices.length, - outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length, - outerNode = linkedList( data, 0, outerLen, dim, true ), - triangles = []; + copy: function ( source ) { - if ( ! outerNode ) return triangles; + Object3D.prototype.copy.call( this, source ); - var minX, minY, maxX, maxY, x, y, invSize; + this.material = source.material; + this.geometry = source.geometry; - if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); + return this; - // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + }, - if ( data.length > 80 * dim ) { + computeLineDistances: function () { - minX = maxX = data[ 0 ]; - minY = maxY = data[ 1 ]; + var geometry = this.geometry; - for ( var i = dim; i < outerLen; i += dim ) { + if ( geometry.isBufferGeometry ) { - 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; + // we assume non-indexed geometry - } + if ( geometry.index === null ) { - // minX, minY and invSize are later used to transform coords into integers for z-order calculation + var positionAttribute = geometry.attributes.position; + var lineDistances = [ 0 ]; - invSize = Math.max( maxX - minX, maxY - minY ); - invSize = invSize !== 0 ? 1 / invSize : 0; + for ( var i = 1, l = positionAttribute.count; i < l; i ++ ) { - } + _start.fromBufferAttribute( positionAttribute, i - 1 ); + _end.fromBufferAttribute( positionAttribute, i ); - earcutLinked( outerNode, triangles, dim, minX, minY, invSize ); + lineDistances[ i ] = lineDistances[ i - 1 ]; + lineDistances[ i ] += _start.distanceTo( _end ); - return triangles; + } - } + geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - }; + } else { - // create a circular doubly linked list from polygon points in the specified winding order + console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - function linkedList( data, start, end, dim, clockwise ) { + } - var i, last; + } else if ( geometry.isGeometry ) { - if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { + var vertices = geometry.vertices; + var lineDistances$1 = geometry.lineDistances; - for ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); + lineDistances$1[ 0 ] = 0; - } else { + for ( var i$1 = 1, l$1 = vertices.length; i$1 < l$1; i$1 ++ ) { - for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); + lineDistances$1[ i$1 ] = lineDistances$1[ i$1 - 1 ]; + lineDistances$1[ i$1 ] += vertices[ i$1 - 1 ].distanceTo( vertices[ i$1 ] ); - } + } - if ( last && equals( last, last.next ) ) { + } - removeNode( last ); - last = last.next; + return this; - } + }, - return last; + raycast: function ( raycaster, intersects ) { - } + var geometry = this.geometry; + var matrixWorld = this.matrixWorld; + var threshold = raycaster.params.Line.threshold; - // eliminate colinear or duplicate points + // Checking boundingSphere distance to ray - function filterPoints( start, end ) { + if ( geometry.boundingSphere === null ) { geometry.computeBoundingSphere(); } - if ( ! start ) return start; - if ( ! end ) end = start; + _sphere$2.copy( geometry.boundingSphere ); + _sphere$2.applyMatrix4( matrixWorld ); + _sphere$2.radius += threshold; - var p = start, again; + if ( raycaster.ray.intersectsSphere( _sphere$2 ) === false ) { return; } - do { + // - again = false; + _inverseMatrix$1.getInverse( matrixWorld ); + _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); - if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { + var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + var localThresholdSq = localThreshold * localThreshold; - removeNode( p ); - p = end = p.prev; - if ( p === p.next ) break; - again = true; + var vStart = new Vector3(); + var vEnd = new Vector3(); + var interSegment = new Vector3(); + var interRay = new Vector3(); + var step = ( this && this.isLineSegments ) ? 2 : 1; - } else { + if ( geometry.isBufferGeometry ) { - p = p.next; + var index = geometry.index; + var attributes = geometry.attributes; + var positions = attributes.position.array; - } + if ( index !== null ) { - } while ( again || p !== end ); + var indices = index.array; - return end; + for ( var i = 0, l = indices.length - 1; i < l; i += step ) { - } + var a = indices[ i ]; + var b = indices[ i + 1 ]; - // main ear slicing loop which triangulates a polygon (given as a linked list) + vStart.fromArray( positions, a * 3 ); + vEnd.fromArray( positions, b * 3 ); - function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { + var distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - if ( ! ear ) return; + if ( distSq > localThresholdSq ) { continue; } - // interlink polygon nodes in z-order + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); + var distance = raycaster.ray.origin.distanceTo( interRay ); - var stop = ear, prev, next; + if ( distance < raycaster.near || distance > raycaster.far ) { continue; } - // iterate through ears, slicing them one by one + intersects.push( { - 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 vertice leads to less sliver triangles - ear = next.next; - stop = next.next; + 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 - continue; + } ); - } + } - ear = next; + } else { - // if we looped through the whole remaining polygon and can't find any more ears + for ( var i$1 = 0, l$1 = positions.length / 3 - 1; i$1 < l$1; i$1 += step ) { - if ( ear === stop ) { + vStart.fromArray( positions, 3 * i$1 ); + vEnd.fromArray( positions, 3 * i$1 + 3 ); - // try filtering points and slicing again + var distSq$1 = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); - if ( ! pass ) { + if ( distSq$1 > localThresholdSq ) { continue; } - earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - // if this didn't work, try curing all small self-intersections locally + var distance$1 = raycaster.ray.origin.distanceTo( interRay ); - } else if ( pass === 1 ) { + if ( distance$1 < raycaster.near || distance$1 > raycaster.far ) { continue; } - ear = cureLocalIntersections( ear, triangles, dim ); - earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); + intersects.push( { - // as a last resort, try splitting the remaining polygon into two + distance: distance$1, + // 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$1, + face: null, + faceIndex: null, + object: this - } else if ( pass === 2 ) { + } ); - splitEarcut( ear, triangles, dim, minX, minY, invSize ); + } } - break; + } else if ( geometry.isGeometry ) { - } + var vertices = geometry.vertices; + var nbVertices = vertices.length; - } + for ( var i$2 = 0; i$2 < nbVertices - 1; i$2 += step ) { - } + var distSq$2 = _ray$1.distanceSqToSegment( vertices[ i$2 ], vertices[ i$2 + 1 ], interRay, interSegment ); - // check whether a polygon node forms a valid ear with adjacent nodes + if ( distSq$2 > localThresholdSq ) { continue; } - function isEar( ear ) { + interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation - var a = ear.prev, - b = ear, - c = ear.next; + var distance$2 = raycaster.ray.origin.distanceTo( interRay ); - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear + if ( distance$2 < raycaster.near || distance$2 > raycaster.far ) { continue; } - // now make sure we don't have other points inside the potential ear - var p = ear.next.next; + intersects.push( { - while ( p !== ear.prev ) { + distance: distance$2, + // 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$2, + face: null, + faceIndex: null, + object: this - 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; + }, - } + updateMorphTargets: function () { - return true; + var geometry = this.geometry; - } + if ( geometry.isBufferGeometry ) { - function isEarHashed( ear, minX, minY, invSize ) { + var morphAttributes = geometry.morphAttributes; + var keys = Object.keys( morphAttributes ); - var a = ear.prev, - b = ear, - c = ear.next; + if ( keys.length > 0 ) { - if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear + var morphAttribute = morphAttributes[ keys[ 0 ] ]; - // triangle bbox; min & max are calculated like this for speed + if ( morphAttribute !== undefined ) { - var 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 ); + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - // z-order range for the current triangle bbox; + for ( var m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - var minZ = zOrder( minTX, minTY, minX, minY, invSize ), - maxZ = zOrder( maxTX, maxTY, minX, minY, invSize ); + var name = morphAttribute[ m ].name || String( m ); - // first look for points inside the triangle in increasing z-order + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; - var p = ear.nextZ; + } - while ( p && p.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.nextZ; + } - } + } else { - // then look for points in decreasing z-order + var morphTargets = geometry.morphTargets; - p = ear.prevZ; + if ( morphTargets !== undefined && morphTargets.length > 0 ) { - while ( p && p.z >= minZ ) { + console.error( 'THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' ); - 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; + } } - return true; + } ); - } + var _start$1 = new Vector3(); + var _end$1 = new Vector3(); - // go through all polygon nodes and cure small local self-intersections + function LineSegments( geometry, material ) { - function cureLocalIntersections( start, triangles, dim ) { + Line.call( this, geometry, material ); - var p = start; + this.type = 'LineSegments'; - do { + } - var a = p.prev, b = p.next.next; + LineSegments.prototype = Object.assign( Object.create( Line.prototype ), { - if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { + constructor: LineSegments, - triangles.push( a.i / dim ); - triangles.push( p.i / dim ); - triangles.push( b.i / dim ); + isLineSegments: true, - // remove two nodes involved + computeLineDistances: function () { - removeNode( p ); - removeNode( p.next ); + var geometry = this.geometry; - p = start = b; + if ( geometry.isBufferGeometry ) { - } + // we assume non-indexed geometry - p = p.next; + if ( geometry.index === null ) { - } while ( p !== start ); + var positionAttribute = geometry.attributes.position; + var lineDistances = []; - return p; + for ( var i = 0, l = positionAttribute.count; i < l; i += 2 ) { - } + _start$1.fromBufferAttribute( positionAttribute, i ); + _end$1.fromBufferAttribute( positionAttribute, i + 1 ); - // try splitting polygon into two and triangulate them independently + lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; + lineDistances[ i + 1 ] = lineDistances[ i ] + _start$1.distanceTo( _end$1 ); - function splitEarcut( start, triangles, dim, minX, minY, invSize ) { + } - // look for a valid diagonal that divides the polygon into two + geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); - var a = start; + } else { - do { + console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); - var b = a.next.next; + } - while ( b !== a.prev ) { + } else if ( geometry.isGeometry ) { - if ( a.i !== b.i && isValidDiagonal( a, b ) ) { + var vertices = geometry.vertices; + var lineDistances$1 = geometry.lineDistances; - // split the polygon in two by the diagonal + for ( var i$1 = 0, l$1 = vertices.length; i$1 < l$1; i$1 += 2 ) { - var c = splitPolygon( a, b ); + _start$1.copy( vertices[ i$1 ] ); + _end$1.copy( vertices[ i$1 + 1 ] ); - // filter colinear points around the cuts + lineDistances$1[ i$1 ] = ( i$1 === 0 ) ? 0 : lineDistances$1[ i$1 - 1 ]; + lineDistances$1[ i$1 + 1 ] = lineDistances$1[ i$1 ] + _start$1.distanceTo( _end$1 ); - 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; + return this; - } + } - b = b.next; + } ); - } + function LineLoop( geometry, material ) { - a = a.next; + Line.call( this, geometry, material ); - } while ( a !== start ); + this.type = 'LineLoop'; } - // link every hole into the outer loop, producing a single-ring polygon without holes - - function eliminateHoles( data, holeIndices, outerNode, dim ) { + LineLoop.prototype = Object.assign( Object.create( Line.prototype ), { - var queue = [], i, len, start, end, list; + constructor: LineLoop, - for ( i = 0, len = holeIndices.length; i < len; i ++ ) { + isLineLoop: true, - 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 ) ); + } ); - } + /** + * parameters = { + * color: , + * opacity: , + * map: new THREE.Texture( ), + * alphaMap: new THREE.Texture( ), + * + * size: , + * sizeAttenuation: + * + * morphTargets: + * } + */ - queue.sort( compareX ); + function PointsMaterial( parameters ) { - // process holes from left to right + Material.call( this ); - for ( i = 0; i < queue.length; i ++ ) { + this.type = 'PointsMaterial'; - eliminateHole( queue[ i ], outerNode ); - outerNode = filterPoints( outerNode, outerNode.next ); + this.color = new Color( 0xffffff ); - } + this.map = null; - return outerNode; + this.alphaMap = null; - } + this.size = 1; + this.sizeAttenuation = true; - function compareX( a, b ) { + this.morphTargets = false; - return a.x - b.x; + this.setValues( parameters ); } - // find a bridge between vertices that connects hole with an outer ring and and link it - - function eliminateHole( hole, outerNode ) { + PointsMaterial.prototype = Object.create( Material.prototype ); + PointsMaterial.prototype.constructor = PointsMaterial; - outerNode = findHoleBridge( hole, outerNode ); + PointsMaterial.prototype.isPointsMaterial = true; - if ( outerNode ) { + PointsMaterial.prototype.copy = function ( source ) { - var b = splitPolygon( outerNode, hole ); + Material.prototype.copy.call( this, source ); - filterPoints( b, b.next ); + this.color.copy( source.color ); - } + this.map = source.map; - } + this.alphaMap = source.alphaMap; - // David Eberly's algorithm for finding a bridge between hole and outer polygon + this.size = source.size; + this.sizeAttenuation = source.sizeAttenuation; - function findHoleBridge( hole, outerNode ) { + this.morphTargets = source.morphTargets; - var p = outerNode, - hx = hole.x, - hy = hole.y, - qx = - Infinity, - m; + return this; - // 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 { + var _inverseMatrix$2 = new Matrix4(); + var _ray$2 = new Ray(); + var _sphere$3 = new Sphere(); + var _position$1 = new Vector3(); - if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { + function Points( geometry, material ) { - var x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); + Object3D.call( this ); - if ( x <= hx && x > qx ) { + this.type = 'Points'; - qx = x; + this.geometry = geometry !== undefined ? geometry : new BufferGeometry(); + this.material = material !== undefined ? material : new PointsMaterial(); - if ( x === hx ) { + this.updateMorphTargets(); - if ( hy === p.y ) return p; - if ( hy === p.next.y ) return p.next; + } - } + Points.prototype = Object.assign( Object.create( Object3D.prototype ), { - m = p.x < p.next.x ? p : p.next; + constructor: Points, - } + isPoints: true, - } + copy: function ( source ) { - p = p.next; + Object3D.prototype.copy.call( this, source ); - } while ( p !== outerNode ); + this.material = source.material; + this.geometry = source.geometry; - if ( ! m ) return null; + return this; - if ( hx === qx ) return m.prev; // hole touches outer segment; pick lower 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 + raycast: function ( raycaster, intersects ) { - var stop = m, - mx = m.x, - my = m.y, - tanMin = Infinity, - tan; + var geometry = this.geometry; + var matrixWorld = this.matrixWorld; + var threshold = raycaster.params.Points.threshold; - p = m.next; + // Checking boundingSphere distance to ray - while ( p !== stop ) { + if ( geometry.boundingSphere === null ) { geometry.computeBoundingSphere(); } - 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 ) ) { + _sphere$3.copy( geometry.boundingSphere ); + _sphere$3.applyMatrix4( matrixWorld ); + _sphere$3.radius += threshold; - tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential + if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) { return; } - if ( ( tan < tanMin || ( tan === tanMin && p.x > m.x ) ) && locallyInside( p, hole ) ) { + // - m = p; - tanMin = tan; + _inverseMatrix$2.getInverse( matrixWorld ); + _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); - } + var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); + var localThresholdSq = localThreshold * localThreshold; - } + if ( geometry.isBufferGeometry ) { - p = p.next; + var index = geometry.index; + var attributes = geometry.attributes; + var positions = attributes.position.array; - } + if ( index !== null ) { - return m; + var indices = index.array; - } + for ( var i = 0, il = indices.length; i < il; i ++ ) { - // interlink polygon nodes in z-order + var a = indices[ i ]; - function indexCurve( start, minX, minY, invSize ) { + _position$1.fromArray( positions, a * 3 ); - var p = start; + testPoint( _position$1, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); - 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; + } else { - } while ( p !== start ); + for ( var i$1 = 0, l = positions.length / 3; i$1 < l; i$1 ++ ) { - p.prevZ.nextZ = null; - p.prevZ = null; + _position$1.fromArray( positions, i$1 * 3 ); - sortLinked( p ); + testPoint( _position$1, i$1, localThresholdSq, matrixWorld, raycaster, intersects, this ); - } + } - // Simon Tatham's linked list merge sort algorithm - // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + } - function sortLinked( list ) { + } else { - var i, p, q, e, tail, numMerges, pSize, qSize, inSize = 1; + var vertices = geometry.vertices; - do { + for ( var i$2 = 0, l$1 = vertices.length; i$2 < l$1; i$2 ++ ) { - p = list; - list = null; - tail = null; - numMerges = 0; + testPoint( vertices[ i$2 ], i$2, localThresholdSq, matrixWorld, raycaster, intersects, this ); - while ( p ) { + } - numMerges ++; - q = p; - pSize = 0; + } - for ( i = 0; i < inSize; i ++ ) { + }, - pSize ++; - q = q.nextZ; - if ( ! q ) break; + updateMorphTargets: function () { - } + var geometry = this.geometry; - qSize = inSize; + if ( geometry.isBufferGeometry ) { - while ( pSize > 0 || ( qSize > 0 && q ) ) { + var morphAttributes = geometry.morphAttributes; + var keys = Object.keys( morphAttributes ); - if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { + if ( keys.length > 0 ) { - e = p; - p = p.nextZ; - pSize --; + var morphAttribute = morphAttributes[ keys[ 0 ] ]; - } else { + if ( morphAttribute !== undefined ) { - e = q; - q = q.nextZ; - qSize --; + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; - } + for ( var m = 0, ml = morphAttribute.length; m < ml; m ++ ) { - if ( tail ) tail.nextZ = e; - else list = e; + var name = morphAttribute[ m ].name || String( m ); - e.prevZ = tail; - tail = e; + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; - } + } - p = q; + } - } + } - tail.nextZ = null; - inSize *= 2; + } else { - } while ( numMerges > 1 ); + var morphTargets = geometry.morphTargets; - return list; + if ( morphTargets !== undefined && morphTargets.length > 0 ) { - } + console.error( 'THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.' ); - // 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; + function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { - y = ( y | ( y << 8 ) ) & 0x00FF00FF; - y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; - y = ( y | ( y << 2 ) ) & 0x33333333; - y = ( y | ( y << 1 ) ) & 0x55555555; + var rayPointDistanceSq = _ray$2.distanceSqToPoint( point ); - return x | ( y << 1 ); + if ( rayPointDistanceSq < localThresholdSq ) { - } + var intersectPoint = new Vector3(); - // find the leftmost node of a polygon ring + _ray$2.closestPointToPoint( point, intersectPoint ); + intersectPoint.applyMatrix4( matrixWorld ); - function getLeftmost( start ) { + var distance = raycaster.ray.origin.distanceTo( intersectPoint ); - var p = start, leftmost = start; + if ( distance < raycaster.near || distance > raycaster.far ) { return; } - do { + intersects.push( { - if ( p.x < leftmost.x ) leftmost = p; - p = p.next; + distance: distance, + distanceToRay: Math.sqrt( rayPointDistanceSq ), + point: intersectPoint, + index: index, + face: null, + object: object - } while ( p !== start ); + } ); - return leftmost; + } } - // check if a point lies within a convex triangle + function VideoTexture( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { + Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - 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; + this.format = format !== undefined ? format : RGBFormat; - } + this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; + this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; - // check if a diagonal between two polygon nodes is valid (lies in polygon interior) + this.generateMipmaps = false; - function isValidDiagonal( a, b ) { + var scope = this; - return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && - locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ); + function updateVideo() { - } + scope.needsUpdate = true; + video.requestVideoFrameCallback( updateVideo ); - // signed area of a triangle + } - function area( p, q, r ) { + if ( 'requestVideoFrameCallback' in video ) { - return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); + video.requestVideoFrameCallback( updateVideo ); + + } } - // check if two points are equal + VideoTexture.prototype = Object.assign( Object.create( Texture.prototype ), { - function equals( p1, p2 ) { + constructor: VideoTexture, - return p1.x === p2.x && p1.y === p2.y; + isVideoTexture: true, - } + update: function () { - // check if two segments intersect + var video = this.image; + var hasVideoFrameCallback = 'requestVideoFrameCallback' in video; - function intersects( p1, q1, p2, q2 ) { + if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { - if ( ( equals( p1, q1 ) && equals( p2, q2 ) ) || - ( equals( p1, q2 ) && equals( p2, q1 ) ) ) return true; + this.needsUpdate = true; - return area( p1, q1, p2 ) > 0 !== area( p1, q1, q2 ) > 0 && - area( p2, q2, p1 ) > 0 !== area( p2, q2, q1 ) > 0; + } - } + } - // check if a polygon diagonal intersects any polygon segments + } ); - function intersectsPolygon( a, b ) { + function CompressedTexture( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding ) { - var p = a; + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); - do { + this.image = { width: width, height: height }; + this.mipmaps = mipmaps; - 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 ) ) { + // no flipping for cube textures + // (also flipping doesn't work for compressed textures ) - return true; + this.flipY = false; - } + // can't generate mipmaps for compressed textures + // mips must be embedded in DDS files - p = p.next; + this.generateMipmaps = false; - } while ( p !== a ); + } - return false; + CompressedTexture.prototype = Object.create( Texture.prototype ); + CompressedTexture.prototype.constructor = CompressedTexture; - } + CompressedTexture.prototype.isCompressedTexture = true; - // check if a polygon diagonal is locally inside the polygon + function CanvasTexture( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { - function locallyInside( a, b ) { + Texture.call( this, canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - 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; + this.needsUpdate = true; } - // check if the middle point of a polygon diagonal is inside the polygon + CanvasTexture.prototype = Object.create( Texture.prototype ); + CanvasTexture.prototype.constructor = CanvasTexture; + CanvasTexture.prototype.isCanvasTexture = true; - function middleInside( a, b ) { + function DepthTexture( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - var p = a, - inside = false, - px = ( a.x + b.x ) / 2, - py = ( a.y + b.y ) / 2; + format = format !== undefined ? format : DepthFormat; - do { + if ( format !== DepthFormat && format !== DepthStencilFormat ) { - 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 ) ) { + throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); - inside = ! inside; + } - } + if ( type === undefined && format === DepthFormat ) { type = UnsignedShortType; } + if ( type === undefined && format === DepthStencilFormat ) { type = UnsignedInt248Type; } - p = p.next; + Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - } while ( p !== a ); + this.image = { width: width, height: height }; - return inside; + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.flipY = false; + this.generateMipmaps = false; } - // 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 + DepthTexture.prototype = Object.create( Texture.prototype ); + DepthTexture.prototype.constructor = DepthTexture; + DepthTexture.prototype.isDepthTexture = true; - function splitPolygon( a, b ) { + function WireframeGeometry( geometry ) { - var a2 = new Node( a.i, a.x, a.y ), - b2 = new Node( b.i, b.x, b.y ), - an = a.next, - bp = b.prev; + BufferGeometry.call( this ); - a.next = b; - b.prev = a; + this.type = 'WireframeGeometry'; - a2.next = an; - an.prev = a2; + // buffer - b2.next = a2; - a2.prev = b2; + var vertices = []; - bp.next = b2; - b2.prev = bp; + // helper variables - return b2; + var edge = [ 0, 0 ], edges = {}; + var keys = [ 'a', 'b', 'c' ]; - } + // different logic for Geometry and BufferGeometry - // create a node and optionally link it with previous one (in a circular doubly linked list) + if ( geometry && geometry.isGeometry ) { - function insertNode( i, x, y, last ) { + // create a data structure that contains all edges without duplicates - var p = new Node( i, x, y ); + var faces = geometry.faces; - if ( ! last ) { + for ( var i = 0, l = faces.length; i < l; i ++ ) { - p.prev = p; - p.next = p; + var face = faces[ i ]; - } else { + for ( var j = 0; j < 3; j ++ ) { - p.next = last.next; - p.prev = last; - last.next.prev = p; - last.next = p; + var edge1 = face[ keys[ j ] ]; + var edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; + edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates + edge[ 1 ] = Math.max( edge1, edge2 ); - } + var key = edge[ 0 ] + ',' + edge[ 1 ]; - return p; + if ( edges[ key ] === undefined ) { - } + edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; - 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; + } - } + // generate vertices - function Node( i, x, y ) { + for ( var key$1 in edges ) { - // vertice index in coordinates array - this.i = i; + var e = edges[ key$1 ]; - // vertex coordinates - this.x = x; - this.y = y; + var vertex = geometry.vertices[ e.index1 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); - // previous and next vertice nodes in a polygon ring - this.prev = null; - this.next = null; + vertex = geometry.vertices[ e.index2 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); - // z-order curve value - this.z = null; + } - // previous and next nodes in z-order - this.prevZ = null; - this.nextZ = null; + } else if ( geometry && geometry.isBufferGeometry ) { - // indicates whether this is a steiner point - this.steiner = false; + var vertex$1 = new Vector3(); - } + if ( geometry.index !== null ) { - function signedArea( data, start, end, dim ) { + // indexed BufferGeometry - var sum = 0; + var position = geometry.attributes.position; + var indices = geometry.index; + var groups = geometry.groups; - for ( var i = start, j = end - dim; i < end; i += dim ) { + if ( groups.length === 0 ) { - sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); - j = i; + groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; - } + } - return sum; + // create a data structure that contains all eges without duplicates - } + for ( var o = 0, ol = groups.length; o < ol; ++ o ) { - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - */ + var group = groups[ o ]; - var ShapeUtils = { + var start = group.start; + var count = group.count; - // calculate area of the contour polygon + for ( var i$1 = start, l$1 = ( start + count ); i$1 < l$1; i$1 += 3 ) { - area: function ( contour ) { + for ( var j$1 = 0; j$1 < 3; j$1 ++ ) { - var n = contour.length; - var a = 0.0; + var edge1$1 = indices.getX( i$1 + j$1 ); + var edge2$1 = indices.getX( i$1 + ( j$1 + 1 ) % 3 ); + edge[ 0 ] = Math.min( edge1$1, edge2$1 ); // sorting prevents duplicates + edge[ 1 ] = Math.max( edge1$1, edge2$1 ); - for ( var p = n - 1, q = 0; q < n; p = q ++ ) { + var key$2 = edge[ 0 ] + ',' + edge[ 1 ]; - a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; + if ( edges[ key$2 ] === undefined ) { - } + edges[ key$2 ] = { index1: edge[ 0 ], index2: edge[ 1 ] }; - return a * 0.5; + } - }, + } - isClockWise: function ( pts ) { + } - return ShapeUtils.area( pts ) < 0; + } - }, + // generate vertices - triangulateShape: function ( contour, holes ) { + for ( var key$3 in edges ) { - var vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] - var holeIndices = []; // array of hole indices - var faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] + var e$1 = edges[ key$3 ]; - removeDupEndPts( contour ); - addContour( vertices, contour ); + vertex$1.fromBufferAttribute( position, e$1.index1 ); + vertices.push( vertex$1.x, vertex$1.y, vertex$1.z ); - // + vertex$1.fromBufferAttribute( position, e$1.index2 ); + vertices.push( vertex$1.x, vertex$1.y, vertex$1.z ); - var holeIndex = contour.length; + } - holes.forEach( removeDupEndPts ); + } else { - for ( var i = 0; i < holes.length; i ++ ) { + // non-indexed BufferGeometry - holeIndices.push( holeIndex ); - holeIndex += holes[ i ].length; - addContour( vertices, holes[ i ] ); + var position$1 = geometry.attributes.position; - } + for ( var i$2 = 0, l$2 = ( position$1.count / 3 ); i$2 < l$2; i$2 ++ ) { - // + for ( var j$2 = 0; j$2 < 3; j$2 ++ ) { - var triangles = Earcut.triangulate( vertices, holeIndices ); + // 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) - // + var index1 = 3 * i$2 + j$2; + vertex$1.fromBufferAttribute( position$1, index1 ); + vertices.push( vertex$1.x, vertex$1.y, vertex$1.z ); - for ( var i = 0; i < triangles.length; i += 3 ) { + var index2 = 3 * i$2 + ( ( j$2 + 1 ) % 3 ); + vertex$1.fromBufferAttribute( position$1, index2 ); + vertices.push( vertex$1.x, vertex$1.y, vertex$1.z ); - faces.push( triangles.slice( i, i + 3 ) ); + } - } + } - return faces; + } } - }; - - function removeDupEndPts( points ) { - - var l = points.length; - - if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { - - points.pop(); + // build geometry - } + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); } - function addContour( vertices, contour ) { - - for ( var i = 0; i < contour.length; i ++ ) { - - vertices.push( contour[ i ].x ); - vertices.push( contour[ i ].y ); - - } - - } + WireframeGeometry.prototype = Object.create( BufferGeometry.prototype ); + WireframeGeometry.prototype.constructor = WireframeGeometry; /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Creates extruded geometry from a path shape. - * - * parameters = { - * - * curveSegments: , // number of points on the curves - * steps: , // number of points for z-side extrusions / used for subdividing 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 is bevel - * bevelSegments: , // number of bevel layers - * - * extrudePath: // curve to extrude shape along - * - * UVGenerator: // object that provides UV generator functions - * - * } + * Parametric Surfaces Geometry + * based on the brilliant article by @prideout https://prideout.net/blog/old/blog/index.html@p=44.html */ - // ExtrudeGeometry + // ParametricGeometry - function ExtrudeGeometry( shapes, options ) { + function ParametricGeometry( func, slices, stacks ) { Geometry.call( this ); - this.type = 'ExtrudeGeometry'; + this.type = 'ParametricGeometry'; this.parameters = { - shapes: shapes, - options: options + func: func, + slices: slices, + stacks: stacks }; - this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) ); + this.fromBufferGeometry( new ParametricBufferGeometry( func, slices, stacks ) ); this.mergeVertices(); } - ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); - ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; - - ExtrudeGeometry.prototype.toJSON = function () { - - var data = Geometry.prototype.toJSON.call( this ); - - var shapes = this.parameters.shapes; - var options = this.parameters.options; - - return toJSON( shapes, options, data ); - - }; + ParametricGeometry.prototype = Object.create( Geometry.prototype ); + ParametricGeometry.prototype.constructor = ParametricGeometry; - // ExtrudeBufferGeometry + // ParametricBufferGeometry - function ExtrudeBufferGeometry( shapes, options ) { + function ParametricBufferGeometry( func, slices, stacks ) { BufferGeometry.call( this ); - this.type = 'ExtrudeBufferGeometry'; + this.type = 'ParametricBufferGeometry'; this.parameters = { - shapes: shapes, - options: options + func: func, + slices: slices, + stacks: stacks }; - shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; + // buffers - var scope = this; + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - var verticesArray = []; - var uvArray = []; + var EPS = 0.00001; - for ( var i = 0, l = shapes.length; i < l; i ++ ) { + var normal = new Vector3(); - var shape = shapes[ i ]; - addShape( shape ); + var p0 = new Vector3(), p1 = new Vector3(); + var pu = new Vector3(), pv = new Vector3(); - } + if ( func.length < 3 ) { - // build geometry + console.error( 'THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.' ); - this.addAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); + } - this.computeVertexNormals(); + // generate vertices, normals and uvs - // functions + var sliceCount = slices + 1; - function addShape( shape ) { + for ( var i = 0; i <= stacks; i ++ ) { - var placeholder = []; + var v = i / stacks; - // options + for ( var j = 0; j <= slices; j ++ ) { - var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; - var steps = options.steps !== undefined ? options.steps : 1; - var depth = options.depth !== undefined ? options.depth : 100; + var u = j / slices; - var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; - var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; - var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; - var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; + // vertex - var extrudePath = options.extrudePath; + func( u, v, p0 ); + vertices.push( p0.x, p0.y, p0.z ); - var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; + // normal - // deprecated options + // approximate tangent vectors via finite differences - if ( options.amount !== undefined ) { + if ( u - EPS >= 0 ) { - console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' ); - depth = options.amount; + func( u - EPS, v, p1 ); + pu.subVectors( p0, p1 ); - } + } else { - // + func( u + EPS, v, p1 ); + pu.subVectors( p1, p0 ); - var extrudePts, extrudeByPath = false; - var splineTube, binormal, normal, position2; + } - if ( extrudePath ) { + if ( v - EPS >= 0 ) { - extrudePts = extrudePath.getSpacedPoints( steps ); + func( u, v - EPS, p1 ); + pv.subVectors( p0, p1 ); - extrudeByPath = true; - bevelEnabled = false; // bevels not supported for path extrusion + } else { - // SETUP TNB variables + func( u, v + EPS, p1 ); + pv.subVectors( p1, p0 ); - // TODO1 - have a .isClosed in spline? + } - splineTube = extrudePath.computeFrenetFrames( steps, false ); + // cross product of tangent vectors returns surface normal - // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); + normal.crossVectors( pu, pv ).normalize(); + normals.push( normal.x, normal.y, normal.z ); - binormal = new Vector3(); - normal = new Vector3(); - position2 = new Vector3(); + // uv + + uvs.push( u, v ); } - // Safeguards if bevels are not enabled + } - if ( ! bevelEnabled ) { + // generate indices - bevelSegments = 0; - bevelThickness = 0; - bevelSize = 0; + for ( var i$1 = 0; i$1 < stacks; i$1 ++ ) { - } + for ( var j$1 = 0; j$1 < slices; j$1 ++ ) { - // Variables initialization + var a = i$1 * sliceCount + j$1; + var b = i$1 * sliceCount + j$1 + 1; + var c = ( i$1 + 1 ) * sliceCount + j$1 + 1; + var d = ( i$1 + 1 ) * sliceCount + j$1; - var ahole, h, hl; // looping of holes + // faces one and two - var shapePoints = shape.extractPoints( curveSegments ); + indices.push( a, b, d ); + indices.push( b, c, d ); - var vertices = shapePoints.shape; - var holes = shapePoints.holes; + } - var reverse = ! ShapeUtils.isClockWise( vertices ); + } - if ( reverse ) { + // build geometry - vertices = vertices.reverse(); + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - // Maybe we should also check if holes are in the opposite direction, just to be safe ... + } - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + ParametricBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + ParametricBufferGeometry.prototype.constructor = ParametricBufferGeometry; - ahole = holes[ h ]; + // PolyhedronGeometry - if ( ShapeUtils.isClockWise( ahole ) ) { + function PolyhedronGeometry( vertices, indices, radius, detail ) { - holes[ h ] = ahole.reverse(); + Geometry.call( this ); - } + this.type = 'PolyhedronGeometry'; - } + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; - } + this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) ); + this.mergeVertices(); + } - var faces = ShapeUtils.triangulateShape( vertices, holes ); + PolyhedronGeometry.prototype = Object.create( Geometry.prototype ); + PolyhedronGeometry.prototype.constructor = PolyhedronGeometry; - /* Vertices */ + // PolyhedronBufferGeometry - var contour = vertices; // vertices has all points but contour has only points of circumference + function PolyhedronBufferGeometry( vertices, indices, radius, detail ) { - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + BufferGeometry.call( this ); - ahole = holes[ h ]; + this.type = 'PolyhedronBufferGeometry'; - vertices = vertices.concat( ahole ); + this.parameters = { + vertices: vertices, + indices: indices, + radius: radius, + detail: detail + }; - } + radius = radius || 1; + detail = detail || 0; + // default buffer data - function scalePt2( pt, vec, size ) { + var vertexBuffer = []; + var uvBuffer = []; - if ( ! vec ) console.error( "THREE.ExtrudeGeometry: vec does not exist" ); + // the subdivision creates the vertex buffer data - return vec.clone().multiplyScalar( size ).add( pt ); + subdivide( detail ); - } + // all vertices should lie on a conceptual sphere with a given radius - var b, bs, t, z, - vert, vlen = vertices.length, - face, flen = faces.length; + applyRadius( radius ); + // finally, create the uv data - // Find directions for point movement + generateUVs(); + // build non-indexed geometry - function getBevelVec( inPt, inPrev, inNext ) { + this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); - // 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. + if ( detail === 0 ) { - var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt + this.computeVertexNormals(); // flat normals - // good reading for geometry algorithms (here: line-line intersection) - // http://geomalgorithms.com/a05-_intersect-1.html + } else { - var v_prev_x = inPt.x - inPrev.x, - v_prev_y = inPt.y - inPrev.y; - var v_next_x = inNext.x - inPt.x, - v_next_y = inNext.y - inPt.y; + this.normalizeNormals(); // smooth normals - var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); + } - // check for collinear edges - var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + // helper functions - if ( Math.abs( collinear0 ) > Number.EPSILON ) { + function subdivide( detail ) { - // not collinear + var a = new Vector3(); + var b = new Vector3(); + var c = new Vector3(); - // length of vectors for normalizing + // iterate over all faces and apply a subdivison with the given detail value - var v_prev_len = Math.sqrt( v_prev_lensq ); - var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); + for ( var i = 0; i < indices.length; i += 3 ) { - // shift adjacent points by unit vectors to the left + // get the vertices of the face - var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); - var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); + getVertexByIndex( indices[ i + 0 ], a ); + getVertexByIndex( indices[ i + 1 ], b ); + getVertexByIndex( indices[ i + 2 ], c ); - var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); - var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); + // perform subdivision - // scaling factor for v_prev to intersection point + subdivideFace( a, b, c, detail ); - var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / - ( v_prev_x * v_next_y - v_prev_y * v_next_x ); + } - // vector from inPt to intersection point + } - v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); - v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); + function subdivideFace( a, b, c, detail ) { - // Don't normalize!, otherwise sharp corners become ugly - // but prevent crazy spikes - var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); - if ( v_trans_lensq <= 2 ) { + var cols = Math.pow( 2, detail ); - return new Vector2( v_trans_x, v_trans_y ); + // we use this multidimensional array as a data structure for creating the subdivision - } else { + var v = []; - shrink_by = Math.sqrt( v_trans_lensq / 2 ); + // construct all of the vertices for this subdivision - } + for ( var i = 0; i <= cols; i ++ ) { - } else { + v[ i ] = []; - // handle special case of collinear edges + var aj = a.clone().lerp( c, i / cols ); + var bj = b.clone().lerp( c, i / cols ); - var direction_eq = false; // assumes: opposite - if ( v_prev_x > Number.EPSILON ) { + var rows = cols - i; - if ( v_next_x > Number.EPSILON ) { + for ( var j = 0; j <= rows; j ++ ) { - direction_eq = true; + if ( j === 0 && i === cols ) { - } + v[ i ][ j ] = aj; } else { - if ( v_prev_x < - Number.EPSILON ) { - - if ( v_next_x < - Number.EPSILON ) { - - direction_eq = true; + v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); - } + } - } else { + } - if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { + } - direction_eq = true; + // construct all of the faces - } + for ( var i$1 = 0; i$1 < cols; i$1 ++ ) { - } + for ( var j$1 = 0; j$1 < 2 * ( cols - i$1 ) - 1; j$1 ++ ) { - } + var k = Math.floor( j$1 / 2 ); - if ( direction_eq ) { + if ( j$1 % 2 === 0 ) { - // 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 ); + pushVertex( v[ i$1 ][ k + 1 ] ); + pushVertex( v[ i$1 + 1 ][ k ] ); + pushVertex( v[ i$1 ][ k ] ); } 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 ); + pushVertex( v[ i$1 ][ k + 1 ] ); + pushVertex( v[ i$1 + 1 ][ k + 1 ] ); + pushVertex( v[ i$1 + 1 ][ k ] ); } } - return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - } + } - var contourMovements = []; - - for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + function applyRadius( radius ) { - if ( j === il ) j = 0; - if ( k === il ) k = 0; + var vertex = new Vector3(); - // (j)---(i)---(k) - // console.log('i,j,k', i, j , k) + // iterate over the entire buffer and apply the radius to each vertex - contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); + for ( var i = 0; i < vertexBuffer.length; i += 3 ) { - } + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; - var holesMovements = [], - oneHoleMovements, verticesMovements = contourMovements.concat(); + vertex.normalize().multiplyScalar( radius ); - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + vertexBuffer[ i + 0 ] = vertex.x; + vertexBuffer[ i + 1 ] = vertex.y; + vertexBuffer[ i + 2 ] = vertex.z; - ahole = holes[ h ]; + } - oneHoleMovements = []; + } - for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { + function generateUVs() { - if ( j === il ) j = 0; - if ( k === il ) k = 0; + var vertex = new Vector3(); - // (j)---(i)---(k) - oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); + for ( var i = 0; i < vertexBuffer.length; i += 3 ) { - } + vertex.x = vertexBuffer[ i + 0 ]; + vertex.y = vertexBuffer[ i + 1 ]; + vertex.z = vertexBuffer[ i + 2 ]; - holesMovements.push( oneHoleMovements ); - verticesMovements = verticesMovements.concat( oneHoleMovements ); + var u = azimuth( vertex ) / 2 / Math.PI + 0.5; + var v = inclination( vertex ) / Math.PI + 0.5; + uvBuffer.push( u, 1 - v ); } + correctUVs(); - // Loop bevelSegments, 1 for the front, 1 for the back + correctSeam(); - for ( b = 0; b < bevelSegments; b ++ ) { + } - //for ( b = bevelSegments; b > 0; b -- ) { + function correctSeam() { - t = b / bevelSegments; - z = bevelThickness * Math.cos( t * Math.PI / 2 ); - bs = bevelSize * Math.sin( t * Math.PI / 2 ); + // handle case when face straddles the seam, see #3269 - // contract shape + for ( var i = 0; i < uvBuffer.length; i += 6 ) { - for ( i = 0, il = contour.length; i < il; i ++ ) { + // uv data of a single face + + var x0 = uvBuffer[ i + 0 ]; + var x1 = uvBuffer[ i + 2 ]; + var x2 = uvBuffer[ i + 4 ]; - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); + var max = Math.max( x0, x1, x2 ); + var min = Math.min( x0, x1, x2 ); - v( vert.x, vert.y, - z ); + // 0.9 is somewhat arbitrary - } + if ( max > 0.9 && min < 0.1 ) { - // expand holes + if ( x0 < 0.2 ) { uvBuffer[ i + 0 ] += 1; } + if ( x1 < 0.2 ) { uvBuffer[ i + 2 ] += 1; } + if ( x2 < 0.2 ) { uvBuffer[ i + 4 ] += 1; } - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + } - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + } - for ( i = 0, il = ahole.length; i < il; i ++ ) { + } - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + function pushVertex( vertex ) { - v( vert.x, vert.y, - z ); + vertexBuffer.push( vertex.x, vertex.y, vertex.z ); - } + } - } + function getVertexByIndex( index, vertex ) { - } + var stride = index * 3; - bs = bevelSize; + vertex.x = vertices[ stride + 0 ]; + vertex.y = vertices[ stride + 1 ]; + vertex.z = vertices[ stride + 2 ]; - // Back facing vertices + } - for ( i = 0; i < vlen; i ++ ) { + function correctUVs() { - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + var a = new Vector3(); + var b = new Vector3(); + var c = new Vector3(); - if ( ! extrudeByPath ) { + var centroid = new Vector3(); - v( vert.x, vert.y, 0 ); + var uvA = new Vector2(); + var uvB = new Vector2(); + var uvC = new Vector2(); - } else { + for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { - // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); + 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 ] ); - normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); - binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); + uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); + uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); + uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); - position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); + centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); - v( position2.x, position2.y, position2.z ); + var azi = azimuth( centroid ); - } + correctUV( uvA, j + 0, a, azi ); + correctUV( uvB, j + 2, b, azi ); + correctUV( uvC, j + 4, c, azi ); } - // Add stepped vertices... - // Including front facing vertices + } - var s; + function correctUV( uv, stride, vector, azimuth ) { - for ( s = 1; s <= steps; s ++ ) { + if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { - for ( i = 0; i < vlen; i ++ ) { + uvBuffer[ stride ] = uv.x - 1; - vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; + } - if ( ! extrudeByPath ) { + if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { - v( vert.x, vert.y, depth / steps * s ); + uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; - } 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 ); + // Angle around the Y axis, counter-clockwise when looking from above. - position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); + function azimuth( vector ) { - v( position2.x, position2.y, position2.z ); + return Math.atan2( vector.z, - vector.x ); - } + } - } - } + // Angle above the XZ plane. + function inclination( vector ) { - // Add bevel segments planes + return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); - //for ( b = 1; b <= bevelSegments; b ++ ) { - for ( b = bevelSegments - 1; b >= 0; b -- ) { + } - t = b / bevelSegments; - z = bevelThickness * Math.cos( t * Math.PI / 2 ); - bs = bevelSize * Math.sin( t * Math.PI / 2 ); + } - // contract shape + PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry; - for ( i = 0, il = contour.length; i < il; i ++ ) { + // TetrahedronGeometry - vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); - v( vert.x, vert.y, depth + z ); + function TetrahedronGeometry( radius, detail ) { - } + Geometry.call( this ); - // expand holes + this.type = 'TetrahedronGeometry'; - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + this.parameters = { + radius: radius, + detail: detail + }; - ahole = holes[ h ]; - oneHoleMovements = holesMovements[ h ]; + this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); - for ( i = 0, il = ahole.length; i < il; i ++ ) { + } - vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); + TetrahedronGeometry.prototype = Object.create( Geometry.prototype ); + TetrahedronGeometry.prototype.constructor = TetrahedronGeometry; - if ( ! extrudeByPath ) { + // TetrahedronBufferGeometry - v( vert.x, vert.y, depth + z ); + function TetrahedronBufferGeometry( radius, detail ) { - } else { + var vertices = [ + 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 + ]; - v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); + var indices = [ + 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 + ]; - } + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - } + this.type = 'TetrahedronBufferGeometry'; - } + this.parameters = { + radius: radius, + detail: detail + }; - } + } - /* Faces */ + TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); + TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry; - // Top and bottom faces + // OctahedronGeometry - buildLidFaces(); + function OctahedronGeometry( radius, detail ) { - // Sides faces + Geometry.call( this ); - buildSideFaces(); + this.type = 'OctahedronGeometry'; + this.parameters = { + radius: radius, + detail: detail + }; - ///// Internal functions + this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); - function buildLidFaces() { + } - var start = verticesArray.length / 3; + OctahedronGeometry.prototype = Object.create( Geometry.prototype ); + OctahedronGeometry.prototype.constructor = OctahedronGeometry; - if ( bevelEnabled ) { + // OctahedronBufferGeometry - var layer = 0; // steps + 1 - var offset = vlen * layer; + function OctahedronBufferGeometry( radius, detail ) { - // Bottom faces + var vertices = [ + 1, 0, 0, - 1, 0, 0, 0, 1, 0, + 0, - 1, 0, 0, 0, 1, 0, 0, - 1 + ]; - for ( i = 0; i < flen; i ++ ) { + var 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 + ]; - face = faces[ i ]; - f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - } + this.type = 'OctahedronBufferGeometry'; - layer = steps + bevelSegments * 2; - offset = vlen * layer; + this.parameters = { + radius: radius, + detail: detail + }; - // Top faces + } - for ( i = 0; i < flen; i ++ ) { + OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); + OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry; - face = faces[ i ]; - f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); + // IcosahedronGeometry - } + function IcosahedronGeometry( radius, detail ) { - } else { + Geometry.call( this ); - // Bottom faces + this.type = 'IcosahedronGeometry'; - for ( i = 0; i < flen; i ++ ) { + this.parameters = { + radius: radius, + detail: detail + }; - face = faces[ i ]; - f3( face[ 2 ], face[ 1 ], face[ 0 ] ); + this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); - } + } - // Top faces + IcosahedronGeometry.prototype = Object.create( Geometry.prototype ); + IcosahedronGeometry.prototype.constructor = IcosahedronGeometry; - for ( i = 0; i < flen; i ++ ) { + // IcosahedronBufferGeometry - face = faces[ i ]; - f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); + function IcosahedronBufferGeometry( radius, detail ) { - } + var t = ( 1 + Math.sqrt( 5 ) ) / 2; - } + var vertices = [ + - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, + 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, + t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 + ]; - scope.addGroup( start, verticesArray.length / 3 - start, 0 ); + var 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 + ]; - } + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - // Create faces for the z-sides of the shape + this.type = 'IcosahedronBufferGeometry'; - function buildSideFaces() { + this.parameters = { + radius: radius, + detail: detail + }; - var start = verticesArray.length / 3; - var layeroffset = 0; - sidewalls( contour, layeroffset ); - layeroffset += contour.length; + } - for ( h = 0, hl = holes.length; h < hl; h ++ ) { + IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); + IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry; - ahole = holes[ h ]; - sidewalls( ahole, layeroffset ); + // DodecahedronGeometry - //, true - layeroffset += ahole.length; + function DodecahedronGeometry( radius, detail ) { - } + Geometry.call( this ); + this.type = 'DodecahedronGeometry'; - scope.addGroup( start, verticesArray.length / 3 - start, 1 ); + this.parameters = { + radius: radius, + detail: detail + }; + this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) ); + this.mergeVertices(); - } + } - function sidewalls( contour, layeroffset ) { + DodecahedronGeometry.prototype = Object.create( Geometry.prototype ); + DodecahedronGeometry.prototype.constructor = DodecahedronGeometry; - var j, k; - i = contour.length; + // DodecahedronBufferGeometry - while ( -- i >= 0 ) { + function DodecahedronBufferGeometry( radius, detail ) { - j = i; - k = i - 1; - if ( k < 0 ) k = contour.length - 1; + var t = ( 1 + Math.sqrt( 5 ) ) / 2; + var r = 1 / t; - //console.log('b', i,j, i-1, k,vertices.length); + var vertices = [ - var s = 0, - sl = steps + bevelSegments * 2; + // (±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, - for ( s = 0; s < sl; s ++ ) { + // (0, ±1/φ, ±φ) + 0, - r, - t, 0, - r, t, + 0, r, - t, 0, r, t, - var slen1 = vlen * s; - var slen2 = vlen * ( s + 1 ); + // (±1/φ, ±φ, 0) + - r, - t, 0, - r, t, 0, + r, - t, 0, r, t, 0, - var a = layeroffset + j + slen1, - b = layeroffset + k + slen1, - c = layeroffset + k + slen2, - d = layeroffset + j + slen2; + // (±φ, 0, ±1/φ) + - t, 0, - r, t, 0, - r, + - t, 0, r, t, 0, r + ]; - f4( a, b, c, d ); + var 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 + ]; - } + PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail ); - } + this.type = 'DodecahedronBufferGeometry'; - } + this.parameters = { + radius: radius, + detail: detail + }; - function v( x, y, z ) { + } - placeholder.push( x ); - placeholder.push( y ); - placeholder.push( z ); + DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype ); + DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry; - } + // TubeGeometry + function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) { - function f3( a, b, c ) { + Geometry.call( this ); - addVertex( a ); - addVertex( b ); - addVertex( c ); + this.type = 'TubeGeometry'; - var nextIndex = verticesArray.length / 3; - var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + this.parameters = { + path: path, + tubularSegments: tubularSegments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); + if ( taper !== undefined ) { console.warn( 'THREE.TubeGeometry: taper has been removed.' ); } - } + var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ); - function f4( a, b, c, d ) { + // expose internals - addVertex( a ); - addVertex( b ); - addVertex( d ); + this.tangents = bufferGeometry.tangents; + this.normals = bufferGeometry.normals; + this.binormals = bufferGeometry.binormals; - addVertex( b ); - addVertex( c ); - addVertex( d ); + // create geometry + this.fromBufferGeometry( bufferGeometry ); + this.mergeVertices(); - var nextIndex = verticesArray.length / 3; - var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + } - addUV( uvs[ 0 ] ); - addUV( uvs[ 1 ] ); - addUV( uvs[ 3 ] ); + TubeGeometry.prototype = Object.create( Geometry.prototype ); + TubeGeometry.prototype.constructor = TubeGeometry; - addUV( uvs[ 1 ] ); - addUV( uvs[ 2 ] ); - addUV( uvs[ 3 ] ); + // TubeBufferGeometry - } + function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) { - function addVertex( index ) { + BufferGeometry.call( this ); - verticesArray.push( placeholder[ index * 3 + 0 ] ); - verticesArray.push( placeholder[ index * 3 + 1 ] ); - verticesArray.push( placeholder[ index * 3 + 2 ] ); + this.type = 'TubeBufferGeometry'; - } + this.parameters = { + path: path, + tubularSegments: tubularSegments, + radius: radius, + radialSegments: radialSegments, + closed: closed + }; + tubularSegments = tubularSegments || 64; + radius = radius || 1; + radialSegments = radialSegments || 8; + closed = closed || false; - function addUV( vector2 ) { + var frames = path.computeFrenetFrames( tubularSegments, closed ); - uvArray.push( vector2.x ); - uvArray.push( vector2.y ); + // expose internals - } + this.tangents = frames.tangents; + this.normals = frames.normals; + this.binormals = frames.binormals; - } + // helper variables - } + var vertex = new Vector3(); + var normal = new Vector3(); + var uv = new Vector2(); + var P = new Vector3(); - ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry; + // buffer - ExtrudeBufferGeometry.prototype.toJSON = function () { + var vertices = []; + var normals = []; + var uvs = []; + var indices = []; - var data = BufferGeometry.prototype.toJSON.call( this ); + // create buffer data - var shapes = this.parameters.shapes; - var options = this.parameters.options; + generateBufferData(); - return toJSON( shapes, options, data ); + // 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 - var WorldUVGenerator = { + function generateBufferData() { - generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { + for ( var i = 0; i < tubularSegments; i ++ ) { - var a_x = vertices[ indexA * 3 ]; - var a_y = vertices[ indexA * 3 + 1 ]; - var b_x = vertices[ indexB * 3 ]; - var b_y = vertices[ indexB * 3 + 1 ]; - var c_x = vertices[ indexC * 3 ]; - var c_y = vertices[ indexC * 3 + 1 ]; + generateSegment( i ); - return [ - new Vector2( a_x, a_y ), - new Vector2( b_x, b_y ), - new Vector2( c_x, c_y ) - ]; + } - }, + // 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) - generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { + generateSegment( ( closed === false ) ? tubularSegments : 0 ); - var a_x = vertices[ indexA * 3 ]; - var a_y = vertices[ indexA * 3 + 1 ]; - var a_z = vertices[ indexA * 3 + 2 ]; - var b_x = vertices[ indexB * 3 ]; - var b_y = vertices[ indexB * 3 + 1 ]; - var b_z = vertices[ indexB * 3 + 2 ]; - var c_x = vertices[ indexC * 3 ]; - var c_y = vertices[ indexC * 3 + 1 ]; - var c_z = vertices[ indexC * 3 + 2 ]; - var d_x = vertices[ indexD * 3 ]; - var d_y = vertices[ indexD * 3 + 1 ]; - var d_z = vertices[ indexD * 3 + 2 ]; + // uvs are generated in a separate function. + // this makes it easy compute correct values for closed geometries - if ( Math.abs( a_y - b_y ) < 0.01 ) { + generateUVs(); - 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 ) - ]; + // finally create faces - } else { + generateIndices(); - 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 generateSegment( i ) { - } - }; + // we use getPointAt to sample evenly distributed points from the given path - function toJSON( shapes, options, data ) { + P = path.getPointAt( i / tubularSegments, P ); - // + // retrieve corresponding normal and binormal - data.shapes = []; + var N = frames.normals[ i ]; + var B = frames.binormals[ i ]; - if ( Array.isArray( shapes ) ) { + // generate normals and vertices for the current segment - for ( var i = 0, l = shapes.length; i < l; i ++ ) { + for ( var j = 0; j <= radialSegments; j ++ ) { - var shape = shapes[ i ]; + var v = j / radialSegments * Math.PI * 2; - data.shapes.push( shape.uuid ); + var sin = Math.sin( v ); + var cos = - Math.cos( v ); - } + // normal - } else { + 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(); - data.shapes.push( shapes.uuid ); + 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; - if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); + vertices.push( vertex.x, vertex.y, vertex.z ); - return data; + } - } + } - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author alteredq / http://alteredqualia.com/ - * - * 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 is bevel - * } - */ - - // TextGeometry - - function TextGeometry( text, parameters ) { + function generateIndices() { - Geometry.call( this ); + for ( var j = 1; j <= tubularSegments; j ++ ) { - this.type = 'TextGeometry'; + for ( var i = 1; i <= radialSegments; i ++ ) { - this.parameters = { - text: text, - parameters: parameters - }; + var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); + var b = ( radialSegments + 1 ) * j + ( i - 1 ); + var c = ( radialSegments + 1 ) * j + i; + var d = ( radialSegments + 1 ) * ( j - 1 ) + i; - this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) ); - this.mergeVertices(); + // faces - } + indices.push( a, b, d ); + indices.push( b, c, d ); - TextGeometry.prototype = Object.create( Geometry.prototype ); - TextGeometry.prototype.constructor = TextGeometry; + } - // TextBufferGeometry + } - function TextBufferGeometry( text, parameters ) { + } - parameters = parameters || {}; + function generateUVs() { - var font = parameters.font; + for ( var i = 0; i <= tubularSegments; i ++ ) { - if ( ! ( font && font.isFont ) ) { + for ( var j = 0; j <= radialSegments; j ++ ) { - console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' ); - return new Geometry(); + uv.x = i / tubularSegments; + uv.y = j / radialSegments; - } + uvs.push( uv.x, uv.y ); - var 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; + TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + TubeBufferGeometry.prototype.constructor = TubeBufferGeometry; - ExtrudeBufferGeometry.call( this, shapes, parameters ); + TubeBufferGeometry.prototype.toJSON = function () { - this.type = 'TextBufferGeometry'; + var data = BufferGeometry.prototype.toJSON.call( this ); - } + data.path = this.parameters.path.toJSON(); - TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype ); - TextBufferGeometry.prototype.constructor = TextBufferGeometry; + return data; - /** - * @author mrdoob / http://mrdoob.com/ - * @author benaadams / https://twitter.com/ben_a_adams - * @author Mugen87 / https://github.com/Mugen87 - */ + }; - // SphereGeometry + // TorusKnotGeometry - function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) { Geometry.call( this ); - this.type = 'SphereGeometry'; + this.type = 'TorusKnotGeometry'; this.parameters = { radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength + tube: tube, + tubularSegments: tubularSegments, + radialSegments: radialSegments, + p: p, + q: q }; - this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); + if ( heightScale !== undefined ) { console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' ); } + + this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) ); this.mergeVertices(); } - SphereGeometry.prototype = Object.create( Geometry.prototype ); - SphereGeometry.prototype.constructor = SphereGeometry; + TorusKnotGeometry.prototype = Object.create( Geometry.prototype ); + TorusKnotGeometry.prototype.constructor = TorusKnotGeometry; - // SphereBufferGeometry + // TorusKnotBufferGeometry - function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { + function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) { BufferGeometry.call( this ); - this.type = 'SphereBufferGeometry'; + this.type = 'TorusKnotBufferGeometry'; this.parameters = { radius: radius, - widthSegments: widthSegments, - heightSegments: heightSegments, - phiStart: phiStart, - phiLength: phiLength, - thetaStart: thetaStart, - thetaLength: thetaLength + tube: tube, + tubularSegments: tubularSegments, + radialSegments: radialSegments, + p: p, + q: q }; radius = radius || 1; + tube = tube || 0.4; + tubularSegments = Math.floor( tubularSegments ) || 64; + radialSegments = Math.floor( radialSegments ) || 8; + p = p || 2; + q = q || 3; - widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); - heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); - - phiStart = phiStart !== undefined ? phiStart : 0; - phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; - - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; - - var thetaEnd = thetaStart + thetaLength; + // buffers - var ix, iy; + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - var index = 0; - var grid = []; + // helper variables var vertex = new Vector3(); var normal = new Vector3(); - // buffers + var P1 = new Vector3(); + var P2 = new Vector3(); - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + var B = new Vector3(); + var T = new Vector3(); + var N = new Vector3(); // generate vertices, normals and uvs - for ( iy = 0; iy <= heightSegments; iy ++ ) { + for ( var i = 0; i <= tubularSegments; ++ i ) { - var verticesRow = []; + // the radian "u" is used to calculate the position on the torus curve of the current tubular segement - var v = iy / heightSegments; + var u = i / tubularSegments * p * Math.PI * 2; - for ( ix = 0; ix <= widthSegments; ix ++ ) { + // 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 - var u = ix / widthSegments; + calculatePositionOnCurve( u, p, q, radius, P1 ); + calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); - // vertex + // calculate orthonormal basis - 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 ); + 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 ( var 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. + + var v = j / radialSegments * Math.PI * 2; + var cx = - tube * Math.cos( v ); + var 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 + // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) + + normal.subVectors( vertex, P1 ).normalize(); - normal.set( vertex.x, vertex.y, vertex.z ).normalize(); normals.push( normal.x, normal.y, normal.z ); // uv - uvs.push( u, 1 - v ); - - verticesRow.push( index ++ ); + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); } - grid.push( verticesRow ); - } - // indices + // generate indices - for ( iy = 0; iy < heightSegments; iy ++ ) { + for ( var j$1 = 1; j$1 <= tubularSegments; j$1 ++ ) { - for ( ix = 0; ix < widthSegments; ix ++ ) { + for ( var i$1 = 1; i$1 <= radialSegments; i$1 ++ ) { - var a = grid[ iy ][ ix + 1 ]; - var b = grid[ iy ][ ix ]; - var c = grid[ iy + 1 ][ ix ]; - var d = grid[ iy + 1 ][ ix + 1 ]; + // indices + + var a = ( radialSegments + 1 ) * ( j$1 - 1 ) + ( i$1 - 1 ); + var b = ( radialSegments + 1 ) * j$1 + ( i$1 - 1 ); + var c = ( radialSegments + 1 ) * j$1 + i$1; + var d = ( radialSegments + 1 ) * ( j$1 - 1 ) + i$1; + + // faces - if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); - if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); + indices.push( a, b, d ); + indices.push( b, c, d ); } @@ -29873,70 +29848,75 @@ // build geometry this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + 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 - SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - SphereBufferGeometry.prototype.constructor = SphereBufferGeometry; + function calculatePositionOnCurve( u, p, q, radius, position ) { - /** - * @author Kaleb Murphy - * @author Mugen87 / https://github.com/Mugen87 - */ + var cu = Math.cos( u ); + var su = Math.sin( u ); + var quOverP = q / p * u; + var cs = Math.cos( quOverP ); - // RingGeometry + position.x = radius * ( 2 + cs ) * 0.5 * cu; + position.y = radius * ( 2 + cs ) * su * 0.5; + position.z = radius * Math.sin( quOverP ) * 0.5; - function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + } + + } + + TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry; + + // TorusGeometry + + function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) { Geometry.call( this ); - this.type = 'RingGeometry'; + this.type = 'TorusGeometry'; this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc }; - this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) ); + this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) ); this.mergeVertices(); } - RingGeometry.prototype = Object.create( Geometry.prototype ); - RingGeometry.prototype.constructor = RingGeometry; + TorusGeometry.prototype = Object.create( Geometry.prototype ); + TorusGeometry.prototype.constructor = TorusGeometry; - // RingBufferGeometry + // TorusBufferGeometry - function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { + function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) { BufferGeometry.call( this ); - this.type = 'RingBufferGeometry'; + this.type = 'TorusBufferGeometry'; this.parameters = { - innerRadius: innerRadius, - outerRadius: outerRadius, - thetaSegments: thetaSegments, - phiSegments: phiSegments, - thetaStart: thetaStart, - thetaLength: thetaLength + radius: radius, + tube: tube, + radialSegments: radialSegments, + tubularSegments: tubularSegments, + arc: arc }; - innerRadius = innerRadius || 0.5; - outerRadius = outerRadius || 1; - - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - - thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; - phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1; + radius = radius || 1; + tube = tube || 0.4; + radialSegments = Math.floor( radialSegments ) || 8; + tubularSegments = Math.floor( tubularSegments ) || 6; + arc = arc || Math.PI * 2; // buffers @@ -29945,65 +29925,58 @@ var normals = []; var uvs = []; - // some helper variables + // helper variables - var segment; - var radius = innerRadius; - var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + var center = new Vector3(); var vertex = new Vector3(); - var uv = new Vector2(); - var j, i; + var normal = new Vector3(); // generate vertices, normals and uvs - for ( j = 0; j <= phiSegments; j ++ ) { + for ( var j = 0; j <= radialSegments; j ++ ) { - for ( i = 0; i <= thetaSegments; i ++ ) { + for ( var i = 0; i <= tubularSegments; i ++ ) { - // values are generate from the inside of the ring to the outside - - segment = thetaStart + i / thetaSegments * thetaLength; + var u = i / tubularSegments * arc; + var v = j / radialSegments * Math.PI * 2; // vertex - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); + 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 - normals.push( 0, 0, 1 ); + center.x = radius * Math.cos( u ); + center.y = radius * Math.sin( u ); + normal.subVectors( vertex, center ).normalize(); - // uv + normals.push( normal.x, normal.y, normal.z ); - uv.x = ( vertex.x / outerRadius + 1 ) / 2; - uv.y = ( vertex.y / outerRadius + 1 ) / 2; + // uv - uvs.push( uv.x, uv.y ); + uvs.push( i / tubularSegments ); + uvs.push( j / radialSegments ); } - // increase the radius for next row of vertices - - radius += radiusStep; - } - // indices - - for ( j = 0; j < phiSegments; j ++ ) { + // generate indices - var thetaSegmentLevel = j * ( thetaSegments + 1 ); + for ( var j$1 = 1; j$1 <= radialSegments; j$1 ++ ) { - for ( i = 0; i < thetaSegments; i ++ ) { + for ( var i$1 = 1; i$1 <= tubularSegments; i$1 ++ ) { - segment = i + thetaSegmentLevel; + // indices - var a = segment; - var b = segment + thetaSegments + 1; - var c = segment + thetaSegments + 2; - var d = segment + 1; + var a = ( tubularSegments + 1 ) * j$1 + i$1 - 1; + var b = ( tubularSegments + 1 ) * ( j$1 - 1 ) + i$1 - 1; + var c = ( tubularSegments + 1 ) * ( j$1 - 1 ) + i$1; + var d = ( tubularSegments + 1 ) * j$1 + i$1; // faces @@ -30017,18162 +29990,20838 @@ // build geometry this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); } - RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - RingBufferGeometry.prototype.constructor = RingBufferGeometry; + TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + TorusBufferGeometry.prototype.constructor = TorusBufferGeometry; /** - * @author zz85 / https://github.com/zz85 - * @author bhouston / http://clara.io - * @author Mugen87 / https://github.com/Mugen87 + * Port from https://github.com/mapbox/earcut (v2.2.2) */ - // LatheGeometry + var Earcut = { - function LatheGeometry( points, segments, phiStart, phiLength ) { + triangulate: function ( data, holeIndices, dim ) { - Geometry.call( this ); + dim = dim || 2; - this.type = 'LatheGeometry'; + var hasHoles = holeIndices && holeIndices.length, + outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length, + outerNode = linkedList( data, 0, outerLen, dim, true ), + triangles = []; - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; + if ( ! outerNode || outerNode.next === outerNode.prev ) { return triangles; } - this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) ); - this.mergeVertices(); + var minX, minY, maxX, maxY, x, y, invSize; - } + if ( hasHoles ) { outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); } - LatheGeometry.prototype = Object.create( Geometry.prototype ); - LatheGeometry.prototype.constructor = LatheGeometry; + // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + if ( data.length > 80 * dim ) { - // LatheBufferGeometry + minX = maxX = data[ 0 ]; + minY = maxY = data[ 1 ]; - function LatheBufferGeometry( points, segments, phiStart, phiLength ) { + for ( var i = dim; i < outerLen; i += dim ) { - BufferGeometry.call( this ); + 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; } - this.type = 'LatheBufferGeometry'; + } - this.parameters = { - points: points, - segments: segments, - phiStart: phiStart, - phiLength: phiLength - }; + // 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; - segments = Math.floor( segments ) || 12; - phiStart = phiStart || 0; - phiLength = phiLength || Math.PI * 2; + } - // clamp phiLength so it's in range of [ 0, 2PI ] + earcutLinked( outerNode, triangles, dim, minX, minY, invSize ); - phiLength = _Math.clamp( phiLength, 0, Math.PI * 2 ); + return triangles; + } - // buffers + }; - var indices = []; - var vertices = []; - var uvs = []; + // create a circular doubly linked list from polygon points in the specified winding order + function linkedList( data, start, end, dim, clockwise ) { - // helper variables + var i, last; - var base; - var inverseSegments = 1.0 / segments; - var vertex = new Vector3(); - var uv = new Vector2(); - var i, j; + if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { - // generate vertices and uvs + for ( i = start; i < end; i += dim ) { last = insertNode( i, data[ i ], data[ i + 1 ], last ); } - for ( i = 0; i <= segments; i ++ ) { + } else { - var phi = phiStart + i * inverseSegments * phiLength; + for ( i = end - dim; i >= start; i -= dim ) { last = insertNode( i, data[ i ], data[ i + 1 ], last ); } - var sin = Math.sin( phi ); - var cos = Math.cos( phi ); + } - for ( j = 0; j <= ( points.length - 1 ); j ++ ) { + if ( last && equals( last, last.next ) ) { - // vertex + removeNode( last ); + last = last.next; - 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 ); + return last; - // uv + } - uv.x = i / segments; - uv.y = j / ( points.length - 1 ); + // eliminate colinear or duplicate points + function filterPoints( start, end ) { - uvs.push( uv.x, uv.y ); + if ( ! start ) { return start; } + if ( ! end ) { end = start; } + var p = start, + again; + do { - } + again = false; - } + if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { - // indices + removeNode( p ); + p = end = p.prev; + if ( p === p.next ) { break; } + again = true; - for ( i = 0; i < segments; i ++ ) { + } else { - for ( j = 0; j < ( points.length - 1 ); j ++ ) { + p = p.next; - base = j + i * points.length; + } - var a = base; - var b = base + points.length; - var c = base + points.length + 1; - var d = base + 1; + } while ( again || p !== end ); - // faces + return end; - indices.push( a, b, d ); - indices.push( b, c, d ); + } - } + // 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; } - // build geometry + // interlink polygon nodes in z-order + if ( ! pass && invSize ) { indexCurve( ear, minX, minY, invSize ); } - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + var stop = ear, + prev, next; - // generate normals + // iterate through ears, slicing them one by one + while ( ear.prev !== ear.next ) { - this.computeVertexNormals(); + prev = ear.prev; + next = ear.next; - // 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 ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { - if ( phiLength === Math.PI * 2 ) { + // cut off the triangle + triangles.push( prev.i / dim ); + triangles.push( ear.i / dim ); + triangles.push( next.i / dim ); - var normals = this.attributes.normal.array; - var n1 = new Vector3(); - var n2 = new Vector3(); - var n = new Vector3(); + removeNode( ear ); - // this is the buffer offset for the last line of vertices + // skipping the next vertex leads to less sliver triangles + ear = next.next; + stop = next.next; - base = segments * points.length * 3; + continue; - for ( i = 0, j = 0; i < points.length; i ++, j += 3 ) { + } - // select the normal of the vertex in the first line + ear = next; - n1.x = normals[ j + 0 ]; - n1.y = normals[ j + 1 ]; - n1.z = normals[ j + 2 ]; + // if we looped through the whole remaining polygon and can't find any more ears + if ( ear === stop ) { - // select the normal of the vertex in the last line + // try filtering points and slicing again + if ( ! pass ) { - n2.x = normals[ base + j + 0 ]; - n2.y = normals[ base + j + 1 ]; - n2.z = normals[ base + j + 2 ]; + earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); - // average normals + // if this didn't work, try curing all small self-intersections locally - n.addVectors( n1, n2 ).normalize(); + } else if ( pass === 1 ) { - // assign the new values to both normals + ear = cureLocalIntersections( filterPoints( ear ), triangles, dim ); + earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); - 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; + // as a last resort, try splitting the remaining polygon into two - } + } else if ( pass === 2 ) { - } + splitEarcut( ear, triangles, dim, minX, minY, invSize ); - } + } - LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - LatheBufferGeometry.prototype.constructor = LatheBufferGeometry; + break; - /** - * @author jonobr1 / http://jonobr1.com - * @author Mugen87 / https://github.com/Mugen87 - */ + } - // ShapeGeometry + } - function ShapeGeometry( shapes, curveSegments ) { + } - Geometry.call( this ); + // check whether a polygon node forms a valid ear with adjacent nodes + function isEar( ear ) { - this.type = 'ShapeGeometry'; + var a = ear.prev, + b = ear, + c = ear.next; - if ( typeof curveSegments === 'object' ) { + if ( area( a, b, c ) >= 0 ) { return false; } // reflex, can't be an ear - console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' ); + // now make sure we don't have other points inside the potential ear + var p = ear.next.next; - curveSegments = curveSegments.curveSegments; + 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; - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; + } - this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) ); - this.mergeVertices(); + return true; } - ShapeGeometry.prototype = Object.create( Geometry.prototype ); - ShapeGeometry.prototype.constructor = ShapeGeometry; + function isEarHashed( ear, minX, minY, invSize ) { - ShapeGeometry.prototype.toJSON = function () { + var a = ear.prev, + b = ear, + c = ear.next; - var data = Geometry.prototype.toJSON.call( this ); + if ( area( a, b, c ) >= 0 ) { return false; } // reflex, can't be an ear - var shapes = this.parameters.shapes; + // triangle bbox; min & max are calculated like this for speed + var 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 ); - return toJSON$1( shapes, data ); + // z-order range for the current triangle bbox; + var minZ = zOrder( minTX, minTY, minX, minY, invSize ), + maxZ = zOrder( maxTX, maxTY, minX, minY, invSize ); - }; + var p = ear.prevZ, + n = ear.nextZ; - // ShapeBufferGeometry + // look for points inside the triangle in both directions + while ( p && p.z >= minZ && n && n.z <= maxZ ) { - function ShapeBufferGeometry( shapes, curveSegments ) { + 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; - BufferGeometry.call( this ); + 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; - this.type = 'ShapeBufferGeometry'; + } - this.parameters = { - shapes: shapes, - curveSegments: curveSegments - }; + // look for remaining points in decreasing z-order + while ( p && p.z >= minZ ) { - curveSegments = curveSegments || 12; + 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; - // buffers + } - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + // look for remaining points in increasing z-order + while ( n && n.z <= maxZ ) { - // helper variables + 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; - var groupStart = 0; - var groupCount = 0; + } - // allow single and array values for "shapes" parameter + return true; - if ( Array.isArray( shapes ) === false ) { + } - addShape( shapes ); + // go through all polygon nodes and cure small local self-intersections + function cureLocalIntersections( start, triangles, dim ) { - } else { + var p = start; + do { - for ( var i = 0; i < shapes.length; i ++ ) { + var a = p.prev, + b = p.next.next; - addShape( shapes[ i ] ); + if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { - this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support + triangles.push( a.i / dim ); + triangles.push( p.i / dim ); + triangles.push( b.i / dim ); - groupStart += groupCount; - groupCount = 0; + // remove two nodes involved + removeNode( p ); + removeNode( p.next ); - } + p = start = b; - } + } - // build geometry + p = p.next; - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + } while ( p !== start ); + return filterPoints( p ); - // helper functions + } - function addShape( shape ) { + // try splitting polygon into two and triangulate them independently + function splitEarcut( start, triangles, dim, minX, minY, invSize ) { - var i, l, shapeHole; + // look for a valid diagonal that divides the polygon into two + var a = start; + do { - var indexOffset = vertices.length / 3; - var points = shape.extractPoints( curveSegments ); + var b = a.next.next; + while ( b !== a.prev ) { - var shapeVertices = points.shape; - var shapeHoles = points.holes; + if ( a.i !== b.i && isValidDiagonal( a, b ) ) { - // check direction of vertices + // split the polygon in two by the diagonal + var c = splitPolygon( a, b ); - if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { + // filter colinear points around the cuts + a = filterPoints( a, a.next ); + c = filterPoints( c, c.next ); - shapeVertices = shapeVertices.reverse(); + // run earcut on each half + earcutLinked( a, triangles, dim, minX, minY, invSize ); + earcutLinked( c, triangles, dim, minX, minY, invSize ); + return; - // also check if holes are in the opposite direction + } - for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { + b = b.next; - shapeHole = shapeHoles[ i ]; + } - if ( ShapeUtils.isClockWise( shapeHole ) === true ) { + a = a.next; - shapeHoles[ i ] = shapeHole.reverse(); + } while ( a !== start ); - } + } - } + // link every hole into the outer loop, producing a single-ring polygon without holes + function eliminateHoles( data, holeIndices, outerNode, dim ) { - } + var queue = [], + i, len, start, end, list; - var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); + for ( i = 0, len = holeIndices.length; i < len; i ++ ) { - // join vertices of inner and outer paths to a single array + 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 ) ); - for ( i = 0, l = shapeHoles.length; i < l; i ++ ) { + } - shapeHole = shapeHoles[ i ]; - shapeVertices = shapeVertices.concat( shapeHole ); + queue.sort( compareX ); - } + // process holes from left to right + for ( i = 0; i < queue.length; i ++ ) { - // vertices, normals, uvs + eliminateHole( queue[ i ], outerNode ); + outerNode = filterPoints( outerNode, outerNode.next ); - for ( i = 0, l = shapeVertices.length; i < l; i ++ ) { + } - var vertex = shapeVertices[ i ]; + return outerNode; - vertices.push( vertex.x, vertex.y, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( vertex.x, vertex.y ); // world uvs + } - } + function compareX( a, b ) { - // incides + return a.x - b.x; - for ( i = 0, l = faces.length; i < l; i ++ ) { + } - var face = faces[ i ]; + // find a bridge between vertices that connects hole with an outer ring and and link it + function eliminateHole( hole, outerNode ) { - var a = face[ 0 ] + indexOffset; - var b = face[ 1 ] + indexOffset; - var c = face[ 2 ] + indexOffset; + outerNode = findHoleBridge( hole, outerNode ); + if ( outerNode ) { - indices.push( a, b, c ); - groupCount += 3; + var b = splitPolygon( outerNode, hole ); - } + // filter collinear points around the cuts + filterPoints( outerNode, outerNode.next ); + filterPoints( b, b.next ); } } - ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; + // David Eberly's algorithm for finding a bridge between hole and outer polygon + function findHoleBridge( hole, outerNode ) { - ShapeBufferGeometry.prototype.toJSON = function () { + var p = outerNode, + hx = hole.x, + hy = hole.y, + qx = - Infinity, + m; - var data = BufferGeometry.prototype.toJSON.call( this ); + // 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 { - var shapes = this.parameters.shapes; + if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { - return toJSON$1( shapes, data ); + var 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; } - function toJSON$1( shapes, data ) { + } - data.shapes = []; + m = p.x < p.next.x ? p : p.next; - if ( Array.isArray( shapes ) ) { + } - for ( var i = 0, l = shapes.length; i < l; i ++ ) { + } - var shape = shapes[ i ]; + p = p.next; - data.shapes.push( shape.uuid ); + } while ( p !== outerNode ); - } + if ( ! m ) { return null; } - } else { + if ( hx === qx ) { return m; } // hole touches outer segment; pick leftmost endpoint - data.shapes.push( shapes.uuid ); + // 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 - } + var stop = m, + mx = m.x, + my = m.y, + tanMin = Infinity, + tan; - return data; + p = m; - } + do { - /** - * @author WestLangley / http://github.com/WestLangley - * @author Mugen87 / https://github.com/Mugen87 - */ + 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 ) ) { - function EdgesGeometry( geometry, thresholdAngle ) { + tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential - BufferGeometry.call( this ); + if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) { - this.type = 'EdgesGeometry'; + m = p; + tanMin = tan; - this.parameters = { - thresholdAngle: thresholdAngle - }; + } - thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; + } - // buffer + p = p.next; - var vertices = []; + } while ( p !== stop ); - // helper variables + return m; - var thresholdDot = Math.cos( _Math.DEG2RAD * thresholdAngle ); - var edge = [ 0, 0 ], edges = {}, edge1, edge2; - var key, keys = [ 'a', 'b', 'c' ]; + } - // prepare source geometry + // whether sector in vertex m contains sector in vertex p in the same coordinates + function sectorContainsSector( m, p ) { - var geometry2; + return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0; - if ( geometry.isBufferGeometry ) { + } - geometry2 = new Geometry(); - geometry2.fromBufferGeometry( geometry ); + // interlink polygon nodes in z-order + function indexCurve( start, minX, minY, invSize ) { - } else { + var p = start; + do { - geometry2 = geometry.clone(); + 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 ); - geometry2.mergeVertices(); - geometry2.computeFaceNormals(); + p.prevZ.nextZ = null; + p.prevZ = null; - var sourceVertices = geometry2.vertices; - var faces = geometry2.faces; + sortLinked( p ); - // now create a data structure where each entry represents an edge with its adjoining faces + } - for ( var i = 0, l = faces.length; i < l; i ++ ) { + // Simon Tatham's linked list merge sort algorithm + // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + function sortLinked( list ) { - var face = faces[ i ]; + var i, p, q, e, tail, numMerges, pSize, qSize, + inSize = 1; - for ( var j = 0; j < 3; j ++ ) { + do { - edge1 = face[ keys[ j ] ]; - edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; - edge[ 0 ] = Math.min( edge1, edge2 ); - edge[ 1 ] = Math.max( edge1, edge2 ); + p = list; + list = null; + tail = null; + numMerges = 0; - key = edge[ 0 ] + ',' + edge[ 1 ]; + while ( p ) { - if ( edges[ key ] === undefined ) { + numMerges ++; + q = p; + pSize = 0; + for ( i = 0; i < inSize; i ++ ) { - edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined }; + pSize ++; + q = q.nextZ; + if ( ! q ) { break; } - } else { + } - edges[ key ].face2 = i; + qSize = inSize; - } + while ( pSize > 0 || ( qSize > 0 && q ) ) { - } + if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { - } + e = p; + p = p.nextZ; + pSize --; - // generate vertices + } else { - for ( key in edges ) { + e = q; + q = q.nextZ; + qSize --; - var e = edges[ key ]; + } - // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree. + if ( tail ) { tail.nextZ = e; } + else { list = e; } - if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) { + e.prevZ = tail; + tail = e; - var vertex = sourceVertices[ e.index1 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); + } - vertex = sourceVertices[ e.index2 ]; - vertices.push( vertex.x, vertex.y, vertex.z ); + p = q; } - } + tail.nextZ = null; + inSize *= 2; - // build geometry + } while ( numMerges > 1 ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + return list; } - EdgesGeometry.prototype = Object.create( BufferGeometry.prototype ); - EdgesGeometry.prototype.constructor = EdgesGeometry; + // z-order of a point given coords and inverse of the longer side of data bbox + function zOrder( x, y, minX, minY, invSize ) { - /** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + // coords are transformed into non-negative 15-bit integer range + x = 32767 * ( x - minX ) * invSize; + y = 32767 * ( y - minY ) * invSize; - // CylinderGeometry + x = ( x | ( x << 8 ) ) & 0x00FF00FF; + x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; + x = ( x | ( x << 2 ) ) & 0x33333333; + x = ( x | ( x << 1 ) ) & 0x55555555; - function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + y = ( y | ( y << 8 ) ) & 0x00FF00FF; + y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; + y = ( y | ( y << 2 ) ) & 0x33333333; + y = ( y | ( y << 1 ) ) & 0x55555555; - Geometry.call( this ); + return x | ( y << 1 ); - this.type = 'CylinderGeometry'; + } - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + // find the leftmost node of a polygon ring + function getLeftmost( start ) { - this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) ); - this.mergeVertices(); + var p = start, + leftmost = start; + do { - } + if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) { leftmost = p; } + p = p.next; - CylinderGeometry.prototype = Object.create( Geometry.prototype ); - CylinderGeometry.prototype.constructor = CylinderGeometry; + } while ( p !== start ); - // CylinderBufferGeometry + return leftmost; - function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + } - BufferGeometry.call( this ); + // check if a point lies within a convex triangle + function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { - this.type = 'CylinderBufferGeometry'; + 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; - this.parameters = { - radiusTop: radiusTop, - radiusBottom: radiusBottom, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + } - var scope = this; + // check if a diagonal between two polygon nodes is valid (lies in polygon interior) + function isValidDiagonal( a, b ) { - radiusTop = radiusTop !== undefined ? radiusTop : 1; - radiusBottom = radiusBottom !== undefined ? radiusBottom : 1; - height = height || 1; + 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 - radialSegments = Math.floor( radialSegments ) || 8; - heightSegments = Math.floor( heightSegments ) || 1; + } - openEnded = openEnded !== undefined ? openEnded : false; - thetaStart = thetaStart !== undefined ? thetaStart : 0.0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + // signed area of a triangle + function area( p, q, r ) { - // buffers + return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + } - // helper variables + // check if two points are equal + function equals( p1, p2 ) { - var index = 0; - var indexArray = []; - var halfHeight = height / 2; - var groupStart = 0; + return p1.x === p2.x && p1.y === p2.y; - // generate geometry + } - generateTorso(); + // check if two segments intersect + function intersects( p1, q1, p2, q2 ) { - if ( openEnded === false ) { + var o1 = sign( area( p1, q1, p2 ) ); + var o2 = sign( area( p1, q1, q2 ) ); + var o3 = sign( area( p2, q2, p1 ) ); + var o4 = sign( area( p2, q2, q1 ) ); - if ( radiusTop > 0 ) generateCap( true ); - if ( radiusBottom > 0 ) generateCap( false ); + 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 - // build geometry + return false; - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + } - function generateTorso() { + // for collinear points p, q, r, check if point q lies on segment pr + function onSegment( p, q, r ) { - var x, y; - var normal = new Vector3(); - var vertex = new Vector3(); + 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 ); - var groupCount = 0; + } - // this will be used to calculate the normal - var slope = ( radiusBottom - radiusTop ) / height; + function sign( num ) { - // generate vertices, normals and uvs + return num > 0 ? 1 : num < 0 ? - 1 : 0; - for ( y = 0; y <= heightSegments; y ++ ) { + } - var indexRow = []; + // check if a polygon diagonal intersects any polygon segments + function intersectsPolygon( a, b ) { - var v = y / heightSegments; + var p = a; + do { - // calculate the radius of the current row + 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; - var radius = v * ( radiusBottom - radiusTop ) + radiusTop; + } while ( p !== a ); - for ( x = 0; x <= radialSegments; x ++ ) { + return false; - var u = x / radialSegments; + } - var theta = u * thetaLength + thetaStart; + // check if a polygon diagonal is locally inside the polygon + function locallyInside( a, b ) { - var sinTheta = Math.sin( theta ); - var cosTheta = Math.cos( theta ); + 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; - // vertex + } - vertex.x = radius * sinTheta; - vertex.y = - v * height + halfHeight; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); + // check if the middle point of a polygon diagonal is inside the polygon + function middleInside( a, b ) { - // normal + var p = a, + inside = false, + px = ( a.x + b.x ) / 2, + py = ( a.y + b.y ) / 2; + do { - normal.set( sinTheta, slope, cosTheta ).normalize(); - normals.push( normal.x, normal.y, normal.z ); + 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; - // uv + } while ( p !== a ); - uvs.push( u, 1 - v ); + return inside; - // save index of vertex in respective row + } - indexRow.push( index ++ ); + // 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 ) { - } + var a2 = new Node( a.i, a.x, a.y ), + b2 = new Node( b.i, b.x, b.y ), + an = a.next, + bp = b.prev; - // now save vertices of the row in our index array + a.next = b; + b.prev = a; - indexArray.push( indexRow ); + a2.next = an; + an.prev = a2; - } + b2.next = a2; + a2.prev = b2; - // generate indices + bp.next = b2; + b2.prev = bp; - for ( x = 0; x < radialSegments; x ++ ) { + return b2; - for ( y = 0; y < heightSegments; y ++ ) { + } - // we use the index array to access the correct indices + // create a node and optionally link it with previous one (in a circular doubly linked list) + function insertNode( i, x, y, last ) { - var a = indexArray[ y ][ x ]; - var b = indexArray[ y + 1 ][ x ]; - var c = indexArray[ y + 1 ][ x + 1 ]; - var d = indexArray[ y ][ x + 1 ]; + var p = new Node( i, x, y ); - // faces + if ( ! last ) { - indices.push( a, b, d ); - indices.push( b, c, d ); + p.prev = p; + p.next = p; - // update group counter + } else { - groupCount += 6; + p.next = last.next; + p.prev = last; + last.next.prev = p; + last.next = p; - } + } - } + return p; - // add a group to the geometry. this will ensure multi material support + } - scope.addGroup( groupStart, groupCount, 0 ); + function removeNode( p ) { - // calculate new start value for groups - - groupStart += groupCount; - - } - - function generateCap( top ) { + p.next.prev = p.prev; + p.prev.next = p.next; - var x, centerIndexStart, centerIndexEnd; + if ( p.prevZ ) { p.prevZ.nextZ = p.nextZ; } + if ( p.nextZ ) { p.nextZ.prevZ = p.prevZ; } - var uv = new Vector2(); - var vertex = new Vector3(); + } - var groupCount = 0; + function Node( i, x, y ) { - var radius = ( top === true ) ? radiusTop : radiusBottom; - var sign = ( top === true ) ? 1 : - 1; + // vertex index in coordinates array + this.i = i; - // save the index of the first center vertex - centerIndexStart = index; + // vertex coordinates + this.x = x; + this.y = y; - // 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 + // previous and next vertex nodes in a polygon ring + this.prev = null; + this.next = null; - for ( x = 1; x <= radialSegments; x ++ ) { + // z-order curve value + this.z = null; - // vertex + // previous and next nodes in z-order + this.prevZ = null; + this.nextZ = null; - vertices.push( 0, halfHeight * sign, 0 ); + // indicates whether this is a steiner point + this.steiner = false; - // normal + } - normals.push( 0, sign, 0 ); + function signedArea( data, start, end, dim ) { - // uv + var sum = 0; + for ( var i = start, j = end - dim; i < end; i += dim ) { - uvs.push( 0.5, 0.5 ); + sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); + j = i; - // increase index + } - index ++; + return sum; - } + } - // save the index of the last center vertex + var ShapeUtils = { - centerIndexEnd = index; + // calculate area of the contour polygon - // now we generate the surrounding vertices, normals and uvs + area: function ( contour ) { - for ( x = 0; x <= radialSegments; x ++ ) { + var n = contour.length; + var a = 0.0; - var u = x / radialSegments; - var theta = u * thetaLength + thetaStart; + for ( var p = n - 1, q = 0; q < n; p = q ++ ) { - var cosTheta = Math.cos( theta ); - var sinTheta = Math.sin( theta ); + a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; - // vertex + } - vertex.x = radius * sinTheta; - vertex.y = halfHeight * sign; - vertex.z = radius * cosTheta; - vertices.push( vertex.x, vertex.y, vertex.z ); + return a * 0.5; - // normal + }, - normals.push( 0, sign, 0 ); + isClockWise: function ( pts ) { - // uv + return ShapeUtils.area( pts ) < 0; - uv.x = ( cosTheta * 0.5 ) + 0.5; - uv.y = ( sinTheta * 0.5 * sign ) + 0.5; - uvs.push( uv.x, uv.y ); + }, - // increase index + triangulateShape: function ( contour, holes ) { - index ++; + var vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] + var holeIndices = []; // array of hole indices + var faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] - } + removeDupEndPts( contour ); + addContour( vertices, contour ); - // generate indices + // - for ( x = 0; x < radialSegments; x ++ ) { + var holeIndex = contour.length; - var c = centerIndexStart + x; - var i = centerIndexEnd + x; + holes.forEach( removeDupEndPts ); - if ( top === true ) { + for ( var i = 0; i < holes.length; i ++ ) { - // face top + holeIndices.push( holeIndex ); + holeIndex += holes[ i ].length; + addContour( vertices, holes[ i ] ); - indices.push( i, i + 1, c ); + } - } else { + // - // face bottom + var triangles = Earcut.triangulate( vertices, holeIndices ); - indices.push( i + 1, i, c ); + // - } + for ( var i$1 = 0; i$1 < triangles.length; i$1 += 3 ) { - groupCount += 3; + faces.push( triangles.slice( i$1, i$1 + 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; + return faces; } - } - - CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry; - - /** - * @author abelnation / http://github.com/abelnation - */ + }; - // ConeGeometry + function removeDupEndPts( points ) { - function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + var l = points.length; - CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { - this.type = 'ConeGeometry'; + points.pop(); - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + } } - ConeGeometry.prototype = Object.create( CylinderGeometry.prototype ); - ConeGeometry.prototype.constructor = ConeGeometry; - - // ConeBufferGeometry - - function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { + function addContour( vertices, contour ) { - CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); + for ( var i = 0; i < contour.length; i ++ ) { - this.type = 'ConeBufferGeometry'; + vertices.push( contour[ i ].x ); + vertices.push( contour[ i ].y ); - this.parameters = { - radius: radius, - height: height, - radialSegments: radialSegments, - heightSegments: heightSegments, - openEnded: openEnded, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + } } - ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype ); - ConeBufferGeometry.prototype.constructor = ConeBufferGeometry; - /** - * @author benaadams / https://twitter.com/ben_a_adams - * @author Mugen87 / https://github.com/Mugen87 - * @author hughes + * 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 + * + * } */ - // CircleGeometry + // ExtrudeGeometry - function CircleGeometry( radius, segments, thetaStart, thetaLength ) { + function ExtrudeGeometry( shapes, options ) { Geometry.call( this ); - this.type = 'CircleGeometry'; + this.type = 'ExtrudeGeometry'; this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength + shapes: shapes, + options: options }; - this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); + this.fromBufferGeometry( new ExtrudeBufferGeometry( shapes, options ) ); this.mergeVertices(); } - CircleGeometry.prototype = Object.create( Geometry.prototype ); - CircleGeometry.prototype.constructor = CircleGeometry; + ExtrudeGeometry.prototype = Object.create( Geometry.prototype ); + ExtrudeGeometry.prototype.constructor = ExtrudeGeometry; - // CircleBufferGeometry + ExtrudeGeometry.prototype.toJSON = function () { - function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) { + var data = Geometry.prototype.toJSON.call( this ); - BufferGeometry.call( this ); + var shapes = this.parameters.shapes; + var options = this.parameters.options; - this.type = 'CircleBufferGeometry'; + return toJSON( shapes, options, data ); - this.parameters = { - radius: radius, - segments: segments, - thetaStart: thetaStart, - thetaLength: thetaLength - }; + }; - radius = radius || 1; - segments = segments !== undefined ? Math.max( 3, segments ) : 8; + // ExtrudeBufferGeometry - thetaStart = thetaStart !== undefined ? thetaStart : 0; - thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; + function ExtrudeBufferGeometry( shapes, options ) { - // buffers + BufferGeometry.call( this ); - var indices = []; - var vertices = []; - var normals = []; - var uvs = []; + this.type = 'ExtrudeBufferGeometry'; - // helper variables + this.parameters = { + shapes: shapes, + options: options + }; - var i, s; - var vertex = new Vector3(); - var uv = new Vector2(); + shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; - // center point + var scope = this; - vertices.push( 0, 0, 0 ); - normals.push( 0, 0, 1 ); - uvs.push( 0.5, 0.5 ); + var verticesArray = []; + var uvArray = []; - for ( s = 0, i = 3; s <= segments; s ++, i += 3 ) { + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - var segment = thetaStart + s / segments * thetaLength; + var shape = shapes[ i ]; + addShape( shape ); - // vertex + } - vertex.x = radius * Math.cos( segment ); - vertex.y = radius * Math.sin( segment ); + // build geometry - vertices.push( vertex.x, vertex.y, vertex.z ); + this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); - // normal + this.computeVertexNormals(); - normals.push( 0, 0, 1 ); + // functions - // uvs + function addShape( shape ) { - uv.x = ( vertices[ i ] / radius + 1 ) / 2; - uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; + var placeholder = []; - uvs.push( uv.x, uv.y ); + // options - } + var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; + var steps = options.steps !== undefined ? options.steps : 1; + var depth = options.depth !== undefined ? options.depth : 100; - // indices + var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; + var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; + var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; + var bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; + var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; - for ( i = 1; i <= segments; i ++ ) { + var extrudePath = options.extrudePath; - indices.push( i, i + 1, 0 ); + var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; - } + // deprecated options - // build geometry + if ( options.amount !== undefined ) { - this.setIndex( indices ); - this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); - this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + console.warn( 'THREE.ExtrudeBufferGeometry: amount has been renamed to depth.' ); + depth = options.amount; - } + } - CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); - CircleBufferGeometry.prototype.constructor = CircleBufferGeometry; + // + var extrudePts, extrudeByPath = false; + var splineTube, binormal, normal, position2; + if ( extrudePath ) { - var Geometries = /*#__PURE__*/Object.freeze({ - WireframeGeometry: WireframeGeometry, - ParametricGeometry: ParametricGeometry, - ParametricBufferGeometry: ParametricBufferGeometry, - TetrahedronGeometry: TetrahedronGeometry, - TetrahedronBufferGeometry: TetrahedronBufferGeometry, - OctahedronGeometry: OctahedronGeometry, - OctahedronBufferGeometry: OctahedronBufferGeometry, - IcosahedronGeometry: IcosahedronGeometry, - IcosahedronBufferGeometry: IcosahedronBufferGeometry, - DodecahedronGeometry: DodecahedronGeometry, - DodecahedronBufferGeometry: DodecahedronBufferGeometry, - PolyhedronGeometry: PolyhedronGeometry, - PolyhedronBufferGeometry: PolyhedronBufferGeometry, - TubeGeometry: TubeGeometry, - TubeBufferGeometry: TubeBufferGeometry, - TorusKnotGeometry: TorusKnotGeometry, - TorusKnotBufferGeometry: TorusKnotBufferGeometry, - TorusGeometry: TorusGeometry, - TorusBufferGeometry: TorusBufferGeometry, - TextGeometry: TextGeometry, - TextBufferGeometry: TextBufferGeometry, - SphereGeometry: SphereGeometry, - SphereBufferGeometry: SphereBufferGeometry, - RingGeometry: RingGeometry, - RingBufferGeometry: RingBufferGeometry, - PlaneGeometry: PlaneGeometry, - PlaneBufferGeometry: PlaneBufferGeometry, - LatheGeometry: LatheGeometry, - LatheBufferGeometry: LatheBufferGeometry, - ShapeGeometry: ShapeGeometry, - ShapeBufferGeometry: ShapeBufferGeometry, - ExtrudeGeometry: ExtrudeGeometry, - ExtrudeBufferGeometry: ExtrudeBufferGeometry, - EdgesGeometry: EdgesGeometry, - ConeGeometry: ConeGeometry, - ConeBufferGeometry: ConeBufferGeometry, - CylinderGeometry: CylinderGeometry, - CylinderBufferGeometry: CylinderBufferGeometry, - CircleGeometry: CircleGeometry, - CircleBufferGeometry: CircleBufferGeometry, - BoxGeometry: BoxGeometry, - BoxBufferGeometry: BoxBufferGeometry - }); + extrudePts = extrudePath.getSpacedPoints( steps ); - /** - * @author mrdoob / http://mrdoob.com/ - * - * parameters = { - * color: - * } - */ + extrudeByPath = true; + bevelEnabled = false; // bevels not supported for path extrusion - function ShadowMaterial( parameters ) { + // SETUP TNB variables - Material.call( this ); + // TODO1 - have a .isClosed in spline? - this.type = 'ShadowMaterial'; + splineTube = extrudePath.computeFrenetFrames( steps, false ); - this.color = new Color( 0x000000 ); - this.transparent = true; + // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); - this.setValues( parameters ); + binormal = new Vector3(); + normal = new Vector3(); + position2 = new Vector3(); - } + } - ShadowMaterial.prototype = Object.create( Material.prototype ); - ShadowMaterial.prototype.constructor = ShadowMaterial; + // Safeguards if bevels are not enabled - ShadowMaterial.prototype.isShadowMaterial = true; + if ( ! bevelEnabled ) { - ShadowMaterial.prototype.copy = function ( source ) { + bevelSegments = 0; + bevelThickness = 0; + bevelSize = 0; + bevelOffset = 0; - Material.prototype.copy.call( this, source ); + } - this.color.copy( source.color ); + // Variables initialization - return this; + var shapePoints = shape.extractPoints( curveSegments ); - }; + var vertices = shapePoints.shape; + var holes = shapePoints.holes; - /** - * @author mrdoob / http://mrdoob.com/ - */ + var reverse = ! ShapeUtils.isClockWise( vertices ); - function RawShaderMaterial( parameters ) { + if ( reverse ) { - ShaderMaterial.call( this, parameters ); + vertices = vertices.reverse(); - this.type = 'RawShaderMaterial'; + // Maybe we should also check if holes are in the opposite direction, just to be safe ... - } + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype ); - RawShaderMaterial.prototype.constructor = RawShaderMaterial; + var ahole = holes[ h ]; - RawShaderMaterial.prototype.isRawShaderMaterial = true; + if ( ShapeUtils.isClockWise( ahole ) ) { - /** - * @author WestLangley / http://github.com/WestLangley - * - * 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: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ + holes[ h ] = ahole.reverse(); - function MeshStandardMaterial( parameters ) { + } - Material.call( this ); + } - this.defines = { 'STANDARD': '' }; + } - this.type = 'MeshStandardMaterial'; - this.color = new Color( 0xffffff ); // diffuse - this.roughness = 0.5; - this.metalness = 0.5; + var faces = ShapeUtils.triangulateShape( vertices, holes ); - this.map = null; + /* Vertices */ - this.lightMap = null; - this.lightMapIntensity = 1.0; + var contour = vertices; // vertices has all points but contour has only points of circumference - this.aoMap = null; - this.aoMapIntensity = 1.0; + for ( var h$1 = 0, hl$1 = holes.length; h$1 < hl$1; h$1 ++ ) { - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; + var ahole$1 = holes[ h$1 ]; - this.bumpMap = null; - this.bumpScale = 1; + vertices = vertices.concat( ahole$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; + function scalePt2( pt, vec, size ) { - this.metalnessMap = null; + if ( ! vec ) { console.error( "THREE.ExtrudeGeometry: vec does not exist" ); } - this.alphaMap = null; + return vec.clone().multiplyScalar( size ).add( pt ); - this.envMap = null; - this.envMapIntensity = 1.0; + } - this.refractionRatio = 0.98; + var vlen = vertices.length, flen = faces.length; - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + // Find directions for point movement - this.setValues( parameters ); - } + function getBevelVec( inPt, inPrev, inNext ) { - MeshStandardMaterial.prototype = Object.create( Material.prototype ); - MeshStandardMaterial.prototype.constructor = MeshStandardMaterial; + // 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. - MeshStandardMaterial.prototype.isMeshStandardMaterial = true; + var v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt - MeshStandardMaterial.prototype.copy = function ( source ) { + // good reading for geometry algorithms (here: line-line intersection) + // http://geomalgorithms.com/a05-_intersect-1.html - Material.prototype.copy.call( this, source ); + var v_prev_x = inPt.x - inPrev.x, + v_prev_y = inPt.y - inPrev.y; + var v_next_x = inNext.x - inPt.x, + v_next_y = inNext.y - inPt.y; - this.defines = { 'STANDARD': '' }; + var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); - this.color.copy( source.color ); - this.roughness = source.roughness; - this.metalness = source.metalness; + // check for collinear edges + var collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - this.map = source.map; + if ( Math.abs( collinear0 ) > Number.EPSILON ) { - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + // not collinear - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + // length of vectors for normalizing - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + var v_prev_len = Math.sqrt( v_prev_lensq ); + var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + // shift adjacent points by unit vectors to the left - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); + var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); + var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); - this.roughnessMap = source.roughnessMap; + // scaling factor for v_prev to intersection point - this.metalnessMap = source.metalnessMap; + var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - + ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / + ( v_prev_x * v_next_y - v_prev_y * v_next_x ); - this.alphaMap = source.alphaMap; + // vector from inPt to intersection point - this.envMap = source.envMap; - this.envMapIntensity = source.envMapIntensity; + v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); + v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); - this.refractionRatio = source.refractionRatio; + // Don't normalize!, otherwise sharp corners become ugly + // but prevent crazy spikes + var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); + if ( v_trans_lensq <= 2 ) { - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + return new Vector2( v_trans_x, v_trans_y ); - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; + } else { - return this; + shrink_by = Math.sqrt( v_trans_lensq / 2 ); - }; + } - /** - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * reflectivity: - * } - */ + } else { - function MeshPhysicalMaterial( parameters ) { + // handle special case of collinear edges - MeshStandardMaterial.call( this ); + var direction_eq = false; // assumes: opposite - this.defines = { 'PHYSICAL': '' }; + if ( v_prev_x > Number.EPSILON ) { - this.type = 'MeshPhysicalMaterial'; + if ( v_next_x > Number.EPSILON ) { - this.reflectivity = 0.5; // maps to F0 = 0.04 + direction_eq = true; - this.clearCoat = 0.0; - this.clearCoatRoughness = 0.0; + } - this.setValues( parameters ); + } else { - } + if ( v_prev_x < - Number.EPSILON ) { - MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype ); - MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial; + if ( v_next_x < - Number.EPSILON ) { - MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true; + direction_eq = true; - MeshPhysicalMaterial.prototype.copy = function ( source ) { + } - MeshStandardMaterial.prototype.copy.call( this, source ); + } else { - this.defines = { 'PHYSICAL': '' }; + if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { - this.reflectivity = source.reflectivity; + direction_eq = true; - this.clearCoat = source.clearCoat; - this.clearCoatRoughness = source.clearCoatRoughness; + } - return this; + } - }; + } - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * 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.Multiply, - * reflectivity: , - * refractionRatio: , - * - * wireframe: , - * wireframeLinewidth: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ + if ( direction_eq ) { - function MeshPhongMaterial( parameters ) { + // 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 ); - Material.call( this ); + } else { - this.type = 'MeshPhongMaterial'; + // 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 ); - this.color = new Color( 0xffffff ); // diffuse - this.specular = new Color( 0x111111 ); - this.shininess = 30; + } - this.map = null; + } - this.lightMap = null; - this.lightMapIntensity = 1.0; + return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); - 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; + var contourMovements = []; - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + if ( j === il ) { j = 0; } + if ( k === il ) { k = 0; } - this.specularMap = null; + // (j)---(i)---(k) + // console.log('i,j,k', i, j , k) - this.alphaMap = null; + contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); - 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'; + var holesMovements = []; + var oneHoleMovements, verticesMovements = contourMovements.concat(); - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + for ( var h$2 = 0, hl$2 = holes.length; h$2 < hl$2; h$2 ++ ) { - this.setValues( parameters ); + var ahole$2 = holes[ h$2 ]; - } + oneHoleMovements = []; - MeshPhongMaterial.prototype = Object.create( Material.prototype ); - MeshPhongMaterial.prototype.constructor = MeshPhongMaterial; + for ( var i$1 = 0, il$1 = ahole$2.length, j$1 = il$1 - 1, k$1 = i$1 + 1; i$1 < il$1; i$1 ++, j$1 ++, k$1 ++ ) { - MeshPhongMaterial.prototype.isMeshPhongMaterial = true; + if ( j$1 === il$1 ) { j$1 = 0; } + if ( k$1 === il$1 ) { k$1 = 0; } - MeshPhongMaterial.prototype.copy = function ( source ) { + // (j)---(i)---(k) + oneHoleMovements[ i$1 ] = getBevelVec( ahole$2[ i$1 ], ahole$2[ j$1 ], ahole$2[ k$1 ] ); - Material.prototype.copy.call( this, source ); + } - this.color.copy( source.color ); - this.specular.copy( source.specular ); - this.shininess = source.shininess; + holesMovements.push( oneHoleMovements ); + verticesMovements = verticesMovements.concat( oneHoleMovements ); - this.map = source.map; + } - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + // Loop bevelSegments, 1 for the front, 1 for the back - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + for ( var b = 0; b < bevelSegments; b ++ ) { - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + //for ( b = bevelSegments; b > 0; b -- ) { - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + var t = b / bevelSegments; + var z = bevelThickness * Math.cos( t * Math.PI / 2 ); + var bs$1 = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + // contract shape - this.specularMap = source.specularMap; + for ( var i$2 = 0, il$2 = contour.length; i$2 < il$2; i$2 ++ ) { - this.alphaMap = source.alphaMap; + var vert = scalePt2( contour[ i$2 ], contourMovements[ i$2 ], bs$1 ); - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; + v( vert.x, vert.y, - z ); - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + } - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; + // expand holes - return this; + for ( var h$3 = 0, hl$3 = holes.length; h$3 < hl$3; h$3 ++ ) { - }; + var ahole$3 = holes[ h$3 ]; + oneHoleMovements = holesMovements[ h$3 ]; - /** - * @author takahirox / http://github.com/takahirox - * - * parameters = { - * gradientMap: new THREE.Texture( ) - * } - */ + for ( var i$3 = 0, il$3 = ahole$3.length; i$3 < il$3; i$3 ++ ) { - function MeshToonMaterial( parameters ) { + var vert$1 = scalePt2( ahole$3[ i$3 ], oneHoleMovements[ i$3 ], bs$1 ); - MeshPhongMaterial.call( this ); + v( vert$1.x, vert$1.y, - z ); - this.defines = { 'TOON': '' }; + } - this.type = 'MeshToonMaterial'; + } - this.gradientMap = null; + } - this.setValues( parameters ); + var bs = bevelSize + bevelOffset; - } + // Back facing vertices - MeshToonMaterial.prototype = Object.create( MeshPhongMaterial.prototype ); - MeshToonMaterial.prototype.constructor = MeshToonMaterial; + for ( var i$4 = 0; i$4 < vlen; i$4 ++ ) { - MeshToonMaterial.prototype.isMeshToonMaterial = true; + var vert$2 = bevelEnabled ? scalePt2( vertices[ i$4 ], verticesMovements[ i$4 ], bs ) : vertices[ i$4 ]; - MeshToonMaterial.prototype.copy = function ( source ) { + if ( ! extrudeByPath ) { - MeshPhongMaterial.prototype.copy.call( this, source ); + v( vert$2.x, vert$2.y, 0 ); - this.gradientMap = source.gradientMap; + } else { - return this; + // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); - }; + normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert$2.x ); + binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert$2.y ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - * - * parameters = { - * opacity: , - * - * bumpMap: new THREE.Texture( ), - * bumpScale: , - * - * normalMap: new THREE.Texture( ), - * normalMapType: THREE.TangentSpaceNormalMap, - * normalScale: , - * - * displacementMap: new THREE.Texture( ), - * displacementScale: , - * displacementBias: , - * - * wireframe: , - * wireframeLinewidth: - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ + position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); - function MeshNormalMaterial( parameters ) { + v( position2.x, position2.y, position2.z ); - Material.call( this ); + } - this.type = 'MeshNormalMaterial'; + } - this.bumpMap = null; - this.bumpScale = 1; + // Add stepped vertices... + // Including front facing vertices - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + for ( var s = 1; s <= steps; s ++ ) { - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + for ( var i$5 = 0; i$5 < vlen; i$5 ++ ) { - this.wireframe = false; - this.wireframeLinewidth = 1; + var vert$3 = bevelEnabled ? scalePt2( vertices[ i$5 ], verticesMovements[ i$5 ], bs ) : vertices[ i$5 ]; - this.fog = false; - this.lights = false; + if ( ! extrudeByPath ) { - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + v( vert$3.x, vert$3.y, depth / steps * s ); - this.setValues( parameters ); + } else { - } + // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); - MeshNormalMaterial.prototype = Object.create( Material.prototype ); - MeshNormalMaterial.prototype.constructor = MeshNormalMaterial; + normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert$3.x ); + binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert$3.y ); - MeshNormalMaterial.prototype.isMeshNormalMaterial = true; + position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); - MeshNormalMaterial.prototype.copy = function ( source ) { + v( position2.x, position2.y, position2.z ); - Material.prototype.copy.call( this, 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; + // Add bevel segments planes - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; + //for ( b = 1; b <= bevelSegments; b ++ ) { + for ( var b$1 = bevelSegments - 1; b$1 >= 0; b$1 -- ) { - return this; + var t$1 = b$1 / bevelSegments; + var z$1 = bevelThickness * Math.cos( t$1 * Math.PI / 2 ); + var bs$2 = bevelSize * Math.sin( t$1 * Math.PI / 2 ) + bevelOffset; - }; + // contract shape - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - * - * 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: , - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ + for ( var i$6 = 0, il$4 = contour.length; i$6 < il$4; i$6 ++ ) { - function MeshLambertMaterial( parameters ) { + var vert$4 = scalePt2( contour[ i$6 ], contourMovements[ i$6 ], bs$2 ); + v( vert$4.x, vert$4.y, depth + z$1 ); - Material.call( this ); + } - this.type = 'MeshLambertMaterial'; + // expand holes - this.color = new Color( 0xffffff ); // diffuse + for ( var h$4 = 0, hl$4 = holes.length; h$4 < hl$4; h$4 ++ ) { - this.map = null; + var ahole$4 = holes[ h$4 ]; + oneHoleMovements = holesMovements[ h$4 ]; - this.lightMap = null; - this.lightMapIntensity = 1.0; + for ( var i$7 = 0, il$5 = ahole$4.length; i$7 < il$5; i$7 ++ ) { - this.aoMap = null; - this.aoMapIntensity = 1.0; + var vert$5 = scalePt2( ahole$4[ i$7 ], oneHoleMovements[ i$7 ], bs$2 ); - this.emissive = new Color( 0x000000 ); - this.emissiveIntensity = 1.0; - this.emissiveMap = null; + if ( ! extrudeByPath ) { - this.specularMap = null; + v( vert$5.x, vert$5.y, depth + z$1 ); - this.alphaMap = null; + } else { - this.envMap = null; - this.combine = MultiplyOperation; - this.reflectivity = 1; - this.refractionRatio = 0.98; + v( vert$5.x, vert$5.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z$1 ); - this.wireframe = false; - this.wireframeLinewidth = 1; - this.wireframeLinecap = 'round'; - this.wireframeLinejoin = 'round'; + } - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + } - this.setValues( parameters ); + } - } + } - MeshLambertMaterial.prototype = Object.create( Material.prototype ); - MeshLambertMaterial.prototype.constructor = MeshLambertMaterial; + /* Faces */ - MeshLambertMaterial.prototype.isMeshLambertMaterial = true; + // Top and bottom faces - MeshLambertMaterial.prototype.copy = function ( source ) { + buildLidFaces(); - Material.prototype.copy.call( this, source ); + // Sides faces - this.color.copy( source.color ); + buildSideFaces(); - this.map = source.map; - this.lightMap = source.lightMap; - this.lightMapIntensity = source.lightMapIntensity; + ///// Internal functions - this.aoMap = source.aoMap; - this.aoMapIntensity = source.aoMapIntensity; + function buildLidFaces() { - this.emissive.copy( source.emissive ); - this.emissiveMap = source.emissiveMap; - this.emissiveIntensity = source.emissiveIntensity; + var start = verticesArray.length / 3; - this.specularMap = source.specularMap; + if ( bevelEnabled ) { - this.alphaMap = source.alphaMap; + var layer = 0; // steps + 1 + var offset = vlen * layer; - this.envMap = source.envMap; - this.combine = source.combine; - this.reflectivity = source.reflectivity; - this.refractionRatio = source.refractionRatio; + // Bottom faces - this.wireframe = source.wireframe; - this.wireframeLinewidth = source.wireframeLinewidth; - this.wireframeLinecap = source.wireframeLinecap; - this.wireframeLinejoin = source.wireframeLinejoin; + for ( var i = 0; i < flen; i ++ ) { - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; + var face = faces[ i ]; + f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); - return this; + } - }; + layer = steps + bevelSegments * 2; + offset = vlen * layer; - /** - * @author WestLangley / http://github.com/WestLangley - * - * 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( ), - * - * skinning: , - * morphTargets: , - * morphNormals: - * } - */ + // Top faces - function MeshMatcapMaterial( parameters ) { + for ( var i$1 = 0; i$1 < flen; i$1 ++ ) { - Material.call( this ); + var face$1 = faces[ i$1 ]; + f3( face$1[ 0 ] + offset, face$1[ 1 ] + offset, face$1[ 2 ] + offset ); - this.defines = { 'MATCAP': '' }; + } - this.type = 'MeshMatcapMaterial'; + } else { - this.color = new Color( 0xffffff ); // diffuse + // Bottom faces - this.matcap = null; + for ( var i$2 = 0; i$2 < flen; i$2 ++ ) { - this.map = null; + var face$2 = faces[ i$2 ]; + f3( face$2[ 2 ], face$2[ 1 ], face$2[ 0 ] ); - this.bumpMap = null; - this.bumpScale = 1; + } - this.normalMap = null; - this.normalMapType = TangentSpaceNormalMap; - this.normalScale = new Vector2( 1, 1 ); + // Top faces - this.displacementMap = null; - this.displacementScale = 1; - this.displacementBias = 0; + for ( var i$3 = 0; i$3 < flen; i$3 ++ ) { - this.alphaMap = null; + var face$3 = faces[ i$3 ]; + f3( face$3[ 0 ] + vlen * steps, face$3[ 1 ] + vlen * steps, face$3[ 2 ] + vlen * steps ); - this.skinning = false; - this.morphTargets = false; - this.morphNormals = false; + } - this.lights = false; + } - this.setValues( parameters ); + scope.addGroup( start, verticesArray.length / 3 - start, 0 ); - // a matcap is required + } - if ( this.matcap === null ) { + // Create faces for the z-sides of the shape - var canvas = document.createElement( 'canvas' ); - canvas.width = 1; - canvas.height = 1; + function buildSideFaces() { - var context = canvas.getContext( '2d' ); + var start = verticesArray.length / 3; + var layeroffset = 0; + sidewalls( contour, layeroffset ); + layeroffset += contour.length; - context.fillStyle = '#fff'; - context.fillRect( 0, 0, 1, 1 ); + for ( var h = 0, hl = holes.length; h < hl; h ++ ) { - this.matcap = new THREE.CanvasTexture( canvas ); + var ahole = holes[ h ]; + sidewalls( ahole, layeroffset ); - } + //, true + layeroffset += ahole.length; - } + } - MeshMatcapMaterial.prototype = Object.create( Material.prototype ); - MeshMatcapMaterial.prototype.constructor = MeshMatcapMaterial; - MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true; + scope.addGroup( start, verticesArray.length / 3 - start, 1 ); - MeshMatcapMaterial.prototype.copy = function ( source ) { - Material.prototype.copy.call( this, source ); + } - this.defines = { 'MATCAP': '' }; + function sidewalls( contour, layeroffset ) { - this.color.copy( source.color ); + var i = contour.length; - this.matcap = source.matcap; + while ( -- i >= 0 ) { - this.map = source.map; + var j = i; + var k = i - 1; + if ( k < 0 ) { k = contour.length - 1; } - this.bumpMap = source.bumpMap; - this.bumpScale = source.bumpScale; + //console.log('b', i,j, i-1, k,vertices.length); - this.normalMap = source.normalMap; - this.normalMapType = source.normalMapType; - this.normalScale.copy( source.normalScale ); + for ( var s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { - this.displacementMap = source.displacementMap; - this.displacementScale = source.displacementScale; - this.displacementBias = source.displacementBias; + var slen1 = vlen * s; + var slen2 = vlen * ( s + 1 ); - this.alphaMap = source.alphaMap; + var a = layeroffset + j + slen1, + b = layeroffset + k + slen1, + c = layeroffset + k + slen2, + d = layeroffset + j + slen2; - this.skinning = source.skinning; - this.morphTargets = source.morphTargets; - this.morphNormals = source.morphNormals; + f4( a, b, c, d ); - return this; + } - }; + } - /** - * @author alteredq / http://alteredqualia.com/ - * - * parameters = { - * color: , - * opacity: , - * - * linewidth: , - * - * scale: , - * dashSize: , - * gapSize: - * } - */ + } - function LineDashedMaterial( parameters ) { + function v( x, y, z ) { - LineBasicMaterial.call( this ); + placeholder.push( x ); + placeholder.push( y ); + placeholder.push( z ); - this.type = 'LineDashedMaterial'; + } - this.scale = 1; - this.dashSize = 3; - this.gapSize = 1; - this.setValues( parameters ); + function f3( a, b, c ) { - } + addVertex( a ); + addVertex( b ); + addVertex( c ); - LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype ); - LineDashedMaterial.prototype.constructor = LineDashedMaterial; + var nextIndex = verticesArray.length / 3; + var uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); - LineDashedMaterial.prototype.isLineDashedMaterial = true; + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); - LineDashedMaterial.prototype.copy = function ( source ) { + } - LineBasicMaterial.prototype.copy.call( this, source ); + function f4( a, b, c, d ) { - this.scale = source.scale; - this.dashSize = source.dashSize; - this.gapSize = source.gapSize; + addVertex( a ); + addVertex( b ); + addVertex( d ); - return this; + addVertex( b ); + addVertex( c ); + addVertex( d ); - }; + var nextIndex = verticesArray.length / 3; + var uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); + addUV( uvs[ 0 ] ); + addUV( uvs[ 1 ] ); + addUV( uvs[ 3 ] ); - var Materials = /*#__PURE__*/Object.freeze({ - 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 - }); + addUV( uvs[ 1 ] ); + addUV( uvs[ 2 ] ); + addUV( uvs[ 3 ] ); - /** - * @author tschw - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ + } - var AnimationUtils = { + function addVertex( index ) { - // same as Array.prototype.slice, but also works on typed arrays - arraySlice: function ( array, from, to ) { + verticesArray.push( placeholder[ index * 3 + 0 ] ); + verticesArray.push( placeholder[ index * 3 + 1 ] ); + verticesArray.push( placeholder[ index * 3 + 2 ] ); - 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 ) ); - } + function addUV( vector2 ) { - return array.slice( from, to ); + uvArray.push( vector2.x ); + uvArray.push( vector2.y ); - }, + } - // 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' ) { + ExtrudeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + ExtrudeBufferGeometry.prototype.constructor = ExtrudeBufferGeometry; - return new type( array ); // create typed array + ExtrudeBufferGeometry.prototype.toJSON = function () { - } + var data = BufferGeometry.prototype.toJSON.call( this ); - return Array.prototype.slice.call( array ); // create Array + var shapes = this.parameters.shapes; + var options = this.parameters.options; - }, + return toJSON( shapes, options, data ); - isTypedArray: function ( object ) { + }; - return ArrayBuffer.isView( object ) && - ! ( object instanceof DataView ); + // - }, + var WorldUVGenerator = { - // returns an array by which times and values can be sorted - getKeyframeOrder: function ( times ) { + generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { - function compareTime( i, j ) { + var a_x = vertices[ indexA * 3 ]; + var a_y = vertices[ indexA * 3 + 1 ]; + var b_x = vertices[ indexB * 3 ]; + var b_y = vertices[ indexB * 3 + 1 ]; + var c_x = vertices[ indexC * 3 ]; + var c_y = vertices[ indexC * 3 + 1 ]; - return times[ i ] - times[ j ]; + return [ + new Vector2( a_x, a_y ), + new Vector2( b_x, b_y ), + new Vector2( c_x, c_y ) + ]; - } + }, - var n = times.length; - var result = new Array( n ); - for ( var i = 0; i !== n; ++ i ) result[ i ] = i; + generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { - result.sort( compareTime ); + var a_x = vertices[ indexA * 3 ]; + var a_y = vertices[ indexA * 3 + 1 ]; + var a_z = vertices[ indexA * 3 + 2 ]; + var b_x = vertices[ indexB * 3 ]; + var b_y = vertices[ indexB * 3 + 1 ]; + var b_z = vertices[ indexB * 3 + 2 ]; + var c_x = vertices[ indexC * 3 ]; + var c_y = vertices[ indexC * 3 + 1 ]; + var c_z = vertices[ indexC * 3 + 2 ]; + var d_x = vertices[ indexD * 3 ]; + var d_y = vertices[ indexD * 3 + 1 ]; + var d_z = vertices[ indexD * 3 + 2 ]; - return result; + if ( Math.abs( a_y - b_y ) < 0.01 ) { - }, + 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 ) + ]; - // uses the array previously returned by 'getKeyframeOrder' to sort data - sortedArray: function ( values, stride, order ) { + } else { - var nValues = values.length; - var result = new values.constructor( nValues ); + 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 ) + ]; - for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { + } - var srcOffset = order[ i ] * stride; + } + }; - for ( var j = 0; j !== stride; ++ j ) { + function toJSON( shapes, options, data ) { - result[ dstOffset ++ ] = values[ srcOffset + j ]; + // - } + data.shapes = []; - } + if ( Array.isArray( shapes ) ) { - return result; + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - }, + var shape = shapes[ i ]; - // function for parsing AOS keyframe formats - flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { + data.shapes.push( shape.uuid ); - var i = 1, key = jsonKeys[ 0 ]; + } - while ( key !== undefined && key[ valuePropertyName ] === undefined ) { + } else { - key = jsonKeys[ i ++ ]; + data.shapes.push( shapes.uuid ); - } + } - if ( key === undefined ) return; // no data + // - var value = key[ valuePropertyName ]; - if ( value === undefined ) return; // no data + if ( options.extrudePath !== undefined ) { data.options.extrudePath = options.extrudePath.toJSON(); } - if ( Array.isArray( value ) ) { + return data; - do { + } - value = key[ valuePropertyName ]; + /** + * 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 + * } + */ - if ( value !== undefined ) { + // TextGeometry - times.push( key.time ); - values.push.apply( values, value ); // push all elements + function TextGeometry( text, parameters ) { - } + Geometry.call( this ); - key = jsonKeys[ i ++ ]; + this.type = 'TextGeometry'; - } while ( key !== undefined ); + this.parameters = { + text: text, + parameters: parameters + }; - } else if ( value.toArray !== undefined ) { + this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) ); + this.mergeVertices(); - // ...assume THREE.Math-ish + } - do { + TextGeometry.prototype = Object.create( Geometry.prototype ); + TextGeometry.prototype.constructor = TextGeometry; - value = key[ valuePropertyName ]; + // TextBufferGeometry - if ( value !== undefined ) { + function TextBufferGeometry( text, parameters ) { - times.push( key.time ); - value.toArray( values, values.length ); + parameters = parameters || {}; - } + var font = parameters.font; - key = jsonKeys[ i ++ ]; + if ( ! ( font && font.isFont ) ) { - } while ( key !== undefined ); + console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' ); + return new Geometry(); - } else { + } - // otherwise push as-is + var shapes = font.generateShapes( text, parameters.size ); - do { + // translate parameters to ExtrudeGeometry API - value = key[ valuePropertyName ]; + parameters.depth = parameters.height !== undefined ? parameters.height : 50; - if ( value !== undefined ) { + // defaults - times.push( key.time ); - values.push( value ); + if ( parameters.bevelThickness === undefined ) { parameters.bevelThickness = 10; } + if ( parameters.bevelSize === undefined ) { parameters.bevelSize = 8; } + if ( parameters.bevelEnabled === undefined ) { parameters.bevelEnabled = false; } - } + ExtrudeBufferGeometry.call( this, shapes, parameters ); - key = jsonKeys[ i ++ ]; + this.type = 'TextBufferGeometry'; - } while ( key !== undefined ); + } - } + TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype ); + TextBufferGeometry.prototype.constructor = TextBufferGeometry; - } + // SphereGeometry - }; + function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - /** - * Abstract base class of interpolants over parametric samples. - * - * The parameter domain is one dimensional, typically the time or a path - * along a curve defined by the data. - * - * The sample values can have any dimensionality and derived classes may - * apply special interpretations to the data. - * - * This class provides the interval seek in a Template Method, deferring - * the actual interpolation to derived classes. - * - * Time complexity is O(1) for linear access crossing at most two points - * and O(log N) for random access, where N is the number of positions. - * - * References: - * - * http://www.oodesign.com/template-method-pattern.html - * - * @author tschw - */ + Geometry.call( this ); - function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + this.type = 'SphereGeometry'; - this.parameterPositions = parameterPositions; - this._cachedIndex = 0; + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - this.resultBuffer = resultBuffer !== undefined ? - resultBuffer : new sampleValues.constructor( sampleSize ); - this.sampleValues = sampleValues; - this.valueSize = sampleSize; + this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) ); + this.mergeVertices(); } - Object.assign( Interpolant.prototype, { + SphereGeometry.prototype = Object.create( Geometry.prototype ); + SphereGeometry.prototype.constructor = SphereGeometry; - evaluate: function ( t ) { + // SphereBufferGeometry - var pp = this.parameterPositions, - i1 = this._cachedIndex, + function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { - t1 = pp[ i1 ], - t0 = pp[ i1 - 1 ]; + BufferGeometry.call( this ); - validate_interval: { + this.type = 'SphereBufferGeometry'; - seek: { + this.parameters = { + radius: radius, + widthSegments: widthSegments, + heightSegments: heightSegments, + phiStart: phiStart, + phiLength: phiLength, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - var right; + radius = radius || 1; - linear_scan: { + widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); + heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); - //- See http://jsperf.com/comparison-to-undefined/3 - //- slower code: - //- - //- if ( t >= t1 || t1 === undefined ) { - forward_scan: if ( ! ( t < t1 ) ) { + phiStart = phiStart !== undefined ? phiStart : 0; + phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; - for ( var giveUpAt = i1 + 2; ; ) { + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; - if ( t1 === undefined ) { + var thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); - if ( t < t0 ) break forward_scan; + var index = 0; + var grid = []; - // after end + var vertex = new Vector3(); + var normal = new Vector3(); - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t, t0 ); + // buffers - } + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - if ( i1 === giveUpAt ) break; // this loop + // generate vertices, normals and uvs - t0 = t1; - t1 = pp[ ++ i1 ]; + for ( var iy = 0; iy <= heightSegments; iy ++ ) { - if ( t < t1 ) { + var verticesRow = []; - // we have arrived at the sought interval - break seek; + var v = iy / heightSegments; - } + // special case for the poles - } + var uOffset = 0; - // prepare binary search on the right side of the index - right = pp.length; - break linear_scan; + if ( iy == 0 && thetaStart == 0 ) { - } + uOffset = 0.5 / widthSegments; - //- slower code: - //- if ( t < t0 || t0 === undefined ) { - if ( ! ( t >= t0 ) ) { + } else if ( iy == heightSegments && thetaEnd == Math.PI ) { - // looping? + uOffset = - 0.5 / widthSegments; - var t1global = pp[ 1 ]; + } - if ( t < t1global ) { + for ( var ix = 0; ix <= widthSegments; ix ++ ) { - i1 = 2; // + 1, using the scan for the details - t0 = t1global; + var u = ix / widthSegments; - } + // vertex - // linear reverse scan + 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 ); - for ( var giveUpAt = i1 - 2; ; ) { + vertices.push( vertex.x, vertex.y, vertex.z ); - if ( t0 === undefined ) { + // normal - // before start + normal.copy( vertex ).normalize(); + normals.push( normal.x, normal.y, normal.z ); - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); + // uv - } + uvs.push( u + uOffset, 1 - v ); - if ( i1 === giveUpAt ) break; // this loop + verticesRow.push( index ++ ); - t1 = t0; - t0 = pp[ -- i1 - 1 ]; + } - if ( t >= t0 ) { + grid.push( verticesRow ); - // we have arrived at the sought interval - break seek; + } - } + // indices - } + for ( var iy$1 = 0; iy$1 < heightSegments; iy$1 ++ ) { - // prepare binary search on the left side of the index - right = i1; - i1 = 0; - break linear_scan; + for ( var ix$1 = 0; ix$1 < widthSegments; ix$1 ++ ) { - } + var a = grid[ iy$1 ][ ix$1 + 1 ]; + var b = grid[ iy$1 ][ ix$1 ]; + var c = grid[ iy$1 + 1 ][ ix$1 ]; + var d = grid[ iy$1 + 1 ][ ix$1 + 1 ]; - // the interval is valid + if ( iy$1 !== 0 || thetaStart > 0 ) { indices.push( a, b, d ); } + if ( iy$1 !== heightSegments - 1 || thetaEnd < Math.PI ) { indices.push( b, c, d ); } - break validate_interval; + } - } // linear scan + } - // binary search + // build geometry - while ( i1 < right ) { + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - var mid = ( i1 + right ) >>> 1; + } - if ( t < pp[ mid ] ) { + SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + SphereBufferGeometry.prototype.constructor = SphereBufferGeometry; - right = mid; + // RingGeometry - } else { + function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - i1 = mid + 1; + Geometry.call( this ); - } + this.type = 'RingGeometry'; - } + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - t1 = pp[ i1 ]; - t0 = pp[ i1 - 1 ]; + this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) ); + this.mergeVertices(); - // check boundary cases, again + } - if ( t0 === undefined ) { + RingGeometry.prototype = Object.create( Geometry.prototype ); + RingGeometry.prototype.constructor = RingGeometry; - this._cachedIndex = 0; - return this.beforeStart_( 0, t, t1 ); + // RingBufferGeometry - } + function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { - if ( t1 === undefined ) { + BufferGeometry.call( this ); - i1 = pp.length; - this._cachedIndex = i1; - return this.afterEnd_( i1 - 1, t0, t ); + this.type = 'RingBufferGeometry'; - } + this.parameters = { + innerRadius: innerRadius, + outerRadius: outerRadius, + thetaSegments: thetaSegments, + phiSegments: phiSegments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - } // seek + innerRadius = innerRadius || 0.5; + outerRadius = outerRadius || 1; - this._cachedIndex = i1; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - this.intervalChanged_( i1, t0, t1 ); + thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; + phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1; - } // validate_interval + // buffers - return this.interpolate_( i1, t0, t, t1 ); + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - }, + // some helper variables - settings: null, // optional, subclass-specific settings structure - // Note: The indirection allows central control of many interpolants. + var radius = innerRadius; + var radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); + var vertex = new Vector3(); + var uv = new Vector2(); - // --- Protected interface + // generate vertices, normals and uvs - DefaultSettings_: {}, + for ( var j = 0; j <= phiSegments; j ++ ) { - getSettings_: function () { + for ( var i = 0; i <= thetaSegments; i ++ ) { - return this.settings || this.DefaultSettings_; + // values are generate from the inside of the ring to the outside - }, + var segment = thetaStart + i / thetaSegments * thetaLength; - copySampleValue_: function ( index ) { + // vertex - // copies a sample value to the result buffer + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, - offset = index * stride; + vertices.push( vertex.x, vertex.y, vertex.z ); - for ( var i = 0; i !== stride; ++ i ) { + // normal - result[ i ] = values[ offset + i ]; + normals.push( 0, 0, 1 ); - } + // uv - return result; + uv.x = ( vertex.x / outerRadius + 1 ) / 2; + uv.y = ( vertex.y / outerRadius + 1 ) / 2; - }, + uvs.push( uv.x, uv.y ); - // Template methods for derived classes: + } - interpolate_: function ( /* i1, t0, t, t1 */ ) { + // increase the radius for next row of vertices - throw new Error( 'call to abstract method' ); - // implementations shall return this.resultBuffer + radius += radiusStep; - }, + } - intervalChanged_: function ( /* i1, t0, t1 */ ) { + // indices - // empty + for ( var j$1 = 0; j$1 < phiSegments; j$1 ++ ) { - } + var thetaSegmentLevel = j$1 * ( thetaSegments + 1 ); - } ); + for ( var i$1 = 0; i$1 < thetaSegments; i$1 ++ ) { - //!\ DECLARE ALIAS AFTER assign prototype ! - Object.assign( Interpolant.prototype, { + var segment$1 = i$1 + thetaSegmentLevel; - //( 0, t, t0 ), returns this.resultBuffer - beforeStart_: Interpolant.prototype.copySampleValue_, + var a = segment$1; + var b = segment$1 + thetaSegments + 1; + var c = segment$1 + thetaSegments + 2; + var d = segment$1 + 1; - //( N-1, tN-1, t ), returns this.resultBuffer - afterEnd_: Interpolant.prototype.copySampleValue_, + // faces - } ); + indices.push( a, b, d ); + indices.push( b, c, d ); - /** - * Fast and simple cubic spline interpolant. - * - * It was derived from a Hermitian construction setting the first derivative - * at each sample position to the linear slope between neighboring positions - * over their parameter interval. - * - * @author tschw - */ + } - function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + } - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + // build geometry - this._weightPrev = - 0; - this._offsetPrev = - 0; - this._weightNext = - 0; - this._offsetNext = - 0; + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); } - CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - - constructor: CubicInterpolant, + RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + RingBufferGeometry.prototype.constructor = RingBufferGeometry; - DefaultSettings_: { + // LatheGeometry - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding + function LatheGeometry( points, segments, phiStart, phiLength ) { - }, + Geometry.call( this ); - intervalChanged_: function ( i1, t0, t1 ) { + this.type = 'LatheGeometry'; - var pp = this.parameterPositions, - iPrev = i1 - 2, - iNext = i1 + 1, + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; - tPrev = pp[ iPrev ], - tNext = pp[ iNext ]; + this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) ); + this.mergeVertices(); - if ( tPrev === undefined ) { + } - switch ( this.getSettings_().endingStart ) { + LatheGeometry.prototype = Object.create( Geometry.prototype ); + LatheGeometry.prototype.constructor = LatheGeometry; - case ZeroSlopeEnding: + // LatheBufferGeometry - // f'(t0) = 0 - iPrev = i1; - tPrev = 2 * t0 - t1; + function LatheBufferGeometry( points, segments, phiStart, phiLength ) { - break; + BufferGeometry.call( this ); - case WrapAroundEnding: + this.type = 'LatheBufferGeometry'; - // use the other end of the curve - iPrev = pp.length - 2; - tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; + this.parameters = { + points: points, + segments: segments, + phiStart: phiStart, + phiLength: phiLength + }; - break; + segments = Math.floor( segments ) || 12; + phiStart = phiStart || 0; + phiLength = phiLength || Math.PI * 2; - default: // ZeroCurvatureEnding + // clamp phiLength so it's in range of [ 0, 2PI ] - // f''(t0) = 0 a.k.a. Natural Spline - iPrev = i1; - tPrev = t1; + phiLength = MathUtils.clamp( phiLength, 0, Math.PI * 2 ); - } - } + // buffers - if ( tNext === undefined ) { + var indices = []; + var vertices = []; + var uvs = []; - switch ( this.getSettings_().endingEnd ) { + // helper variables - case ZeroSlopeEnding: + var inverseSegments = 1.0 / segments; + var vertex = new Vector3(); + var uv = new Vector2(); - // f'(tN) = 0 - iNext = i1; - tNext = 2 * t1 - t0; + // generate vertices and uvs - break; + for ( var i = 0; i <= segments; i ++ ) { - case WrapAroundEnding: + var phi = phiStart + i * inverseSegments * phiLength; - // use the other end of the curve - iNext = 1; - tNext = t1 + pp[ 1 ] - pp[ 0 ]; + var sin = Math.sin( phi ); + var cos = Math.cos( phi ); - break; + for ( var j = 0; j <= ( points.length - 1 ); j ++ ) { - default: // ZeroCurvatureEnding + // vertex - // f''(tN) = 0, a.k.a. Natural Spline - iNext = i1 - 1; - tNext = t0; + 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 - var halfDt = ( t1 - t0 ) * 0.5, - stride = this.valueSize; + uv.x = i / segments; + uv.y = j / ( points.length - 1 ); - this._weightPrev = halfDt / ( t0 - tPrev ); - this._weightNext = halfDt / ( tNext - t1 ); - this._offsetPrev = iPrev * stride; - this._offsetNext = iNext * stride; + uvs.push( uv.x, uv.y ); - }, - interpolate_: function ( i1, t0, t, t1 ) { + } - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + } - o1 = i1 * stride, o0 = o1 - stride, - oP = this._offsetPrev, oN = this._offsetNext, - wP = this._weightPrev, wN = this._weightNext, + // indices - p = ( t - t0 ) / ( t1 - t0 ), - pp = p * p, - ppp = pp * p; + for ( var i$1 = 0; i$1 < segments; i$1 ++ ) { - // evaluate polynomials + for ( var j$1 = 0; j$1 < ( points.length - 1 ); j$1 ++ ) { - var sP = - wP * ppp + 2 * wP * pp - wP * p; - var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; - var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; - var sN = wN * ppp - wN * pp; + var base = j$1 + i$1 * points.length; - // combine data linearly + var a = base; + var b = base + points.length; + var c = base + points.length + 1; + var d = base + 1; - for ( var i = 0; i !== stride; ++ i ) { + // faces - result[ i ] = - sP * values[ oP + i ] + - s0 * values[ o0 + i ] + - s1 * values[ o1 + i ] + - sN * values[ oN + i ]; + indices.push( a, b, d ); + indices.push( b, c, d ); } - return result; - } - } ); + // build geometry - /** - * @author tschw - */ + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + // generate normals - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + 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). - LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + if ( phiLength === Math.PI * 2 ) { - constructor: LinearInterpolant, + var normals = this.attributes.normal.array; + var n1 = new Vector3(); + var n2 = new Vector3(); + var n = new Vector3(); - interpolate_: function ( i1, t0, t, t1 ) { + // this is the buffer offset for the last line of vertices - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + var base$1 = segments * points.length * 3; - offset1 = i1 * stride, - offset0 = offset1 - stride, + for ( var i$2 = 0, j$2 = 0; i$2 < points.length; i$2 ++, j$2 += 3 ) { - weight1 = ( t - t0 ) / ( t1 - t0 ), - weight0 = 1 - weight1; + // select the normal of the vertex in the first line - for ( var i = 0; i !== stride; ++ i ) { + n1.x = normals[ j$2 + 0 ]; + n1.y = normals[ j$2 + 1 ]; + n1.z = normals[ j$2 + 2 ]; - result[ i ] = - values[ offset0 + i ] * weight0 + - values[ offset1 + i ] * weight1; + // select the normal of the vertex in the last line - } + n2.x = normals[ base$1 + j$2 + 0 ]; + n2.y = normals[ base$1 + j$2 + 1 ]; + n2.z = normals[ base$1 + j$2 + 2 ]; - return result; + // average normals - } + n.addVectors( n1, n2 ).normalize(); - } ); + // assign the new values to both normals - /** - * - * Interpolant that evaluates to the sample value at the position preceeding - * the parameter. - * - * @author tschw - */ + normals[ j$2 + 0 ] = normals[ base$1 + j$2 + 0 ] = n.x; + normals[ j$2 + 1 ] = normals[ base$1 + j$2 + 1 ] = n.y; + normals[ j$2 + 2 ] = normals[ base$1 + j$2 + 2 ] = n.z; - function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + } - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + } } - DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - - constructor: DiscreteInterpolant, + LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + LatheBufferGeometry.prototype.constructor = LatheBufferGeometry; - interpolate_: function ( i1 /*, t0, t, t1 */ ) { + // ShapeGeometry - return this.copySampleValue_( i1 - 1 ); + function ShapeGeometry( shapes, curveSegments ) { - } + Geometry.call( this ); - } ); + this.type = 'ShapeGeometry'; - /** - * - * A timed sequence of keyframes for a specific property. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + if ( typeof curveSegments === 'object' ) { - function KeyframeTrack( name, times, values, interpolation ) { + console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' ); - 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 ); + curveSegments = curveSegments.curveSegments; - this.name = name; + } - this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); - this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); + this.parameters = { + shapes: shapes, + curveSegments: curveSegments + }; - this.setInterpolation( interpolation || this.DefaultInterpolation ); + this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) ); + this.mergeVertices(); } - // Static methods + ShapeGeometry.prototype = Object.create( Geometry.prototype ); + ShapeGeometry.prototype.constructor = ShapeGeometry; - Object.assign( KeyframeTrack, { + ShapeGeometry.prototype.toJSON = function () { - // Serialization (in static context, because of constructor invocation - // and automatic invocation of .toJSON): + var data = Geometry.prototype.toJSON.call( this ); - toJSON: function ( track ) { + var shapes = this.parameters.shapes; - var trackType = track.constructor; + return toJSON$1( shapes, data ); - var json; + }; - // derived classes can define a static toJSON method - if ( trackType.toJSON !== undefined ) { + // ShapeBufferGeometry - json = trackType.toJSON( track ); + function ShapeBufferGeometry( shapes, curveSegments ) { - } else { + BufferGeometry.call( this ); - // by default, we assume the data can be serialized as-is - json = { + this.type = 'ShapeBufferGeometry'; - 'name': track.name, - 'times': AnimationUtils.convertArray( track.times, Array ), - 'values': AnimationUtils.convertArray( track.values, Array ) + this.parameters = { + shapes: shapes, + curveSegments: curveSegments + }; - }; + curveSegments = curveSegments || 12; - var interpolation = track.getInterpolation(); + // buffers - if ( interpolation !== track.DefaultInterpolation ) { + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - json.interpolation = interpolation; + // helper variables - } + var groupStart = 0; + var groupCount = 0; - } + // allow single and array values for "shapes" parameter - json.type = track.ValueTypeName; // mandatory + if ( Array.isArray( shapes ) === false ) { - return json; + addShape( shapes ); - } + } else { - } ); + for ( var i = 0; i < shapes.length; i ++ ) { - Object.assign( KeyframeTrack.prototype, { + addShape( shapes[ i ] ); - constructor: KeyframeTrack, + this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support - TimeBufferType: Float32Array, + groupStart += groupCount; + groupCount = 0; - ValueBufferType: Float32Array, + } - DefaultInterpolation: InterpolateLinear, + } - InterpolantFactoryMethodDiscrete: function ( result ) { + // build geometry - return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - }, - InterpolantFactoryMethodLinear: function ( result ) { + // helper functions - return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); + function addShape( shape ) { - }, + var indexOffset = vertices.length / 3; + var points = shape.extractPoints( curveSegments ); - InterpolantFactoryMethodSmooth: function ( result ) { + var shapeVertices = points.shape; + var shapeHoles = points.holes; - return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); + // check direction of vertices - }, + if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { - setInterpolation: function ( interpolation ) { + shapeVertices = shapeVertices.reverse(); - var factoryMethod; + } - switch ( interpolation ) { + for ( var i = 0, l = shapeHoles.length; i < l; i ++ ) { - case InterpolateDiscrete: + var shapeHole = shapeHoles[ i ]; - factoryMethod = this.InterpolantFactoryMethodDiscrete; + if ( ShapeUtils.isClockWise( shapeHole ) === true ) { - break; + shapeHoles[ i ] = shapeHole.reverse(); - case InterpolateLinear: + } - factoryMethod = this.InterpolantFactoryMethodLinear; + } - break; + var faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); - case InterpolateSmooth: + // join vertices of inner and outer paths to a single array - factoryMethod = this.InterpolantFactoryMethodSmooth; + for ( var i$1 = 0, l$1 = shapeHoles.length; i$1 < l$1; i$1 ++ ) { - break; + var shapeHole$1 = shapeHoles[ i$1 ]; + shapeVertices = shapeVertices.concat( shapeHole$1 ); } - if ( factoryMethod === undefined ) { + // vertices, normals, uvs - var message = "unsupported interpolation for " + - this.ValueTypeName + " keyframe track named " + this.name; + for ( var i$2 = 0, l$2 = shapeVertices.length; i$2 < l$2; i$2 ++ ) { - if ( this.createInterpolant === undefined ) { + var vertex = shapeVertices[ i$2 ]; - // fall back to default, unless the default itself is messed up - if ( interpolation !== this.DefaultInterpolation ) { + vertices.push( vertex.x, vertex.y, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( vertex.x, vertex.y ); // world uvs - this.setInterpolation( this.DefaultInterpolation ); + } - } else { + // incides - throw new Error( message ); // fatal, in this case + for ( var i$3 = 0, l$3 = faces.length; i$3 < l$3; i$3 ++ ) { - } + var face = faces[ i$3 ]; - } + var a = face[ 0 ] + indexOffset; + var b = face[ 1 ] + indexOffset; + var c = face[ 2 ] + indexOffset; - console.warn( 'THREE.KeyframeTrack:', message ); - return this; + indices.push( a, b, c ); + groupCount += 3; } - this.createInterpolant = factoryMethod; + } - return this; + } - }, + ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry; - getInterpolation: function () { + ShapeBufferGeometry.prototype.toJSON = function () { - switch ( this.createInterpolant ) { + var data = BufferGeometry.prototype.toJSON.call( this ); - case this.InterpolantFactoryMethodDiscrete: + var shapes = this.parameters.shapes; - return InterpolateDiscrete; + return toJSON$1( shapes, data ); - case this.InterpolantFactoryMethodLinear: + }; - return InterpolateLinear; + // - case this.InterpolantFactoryMethodSmooth: + function toJSON$1( shapes, data ) { - return InterpolateSmooth; + data.shapes = []; - } + if ( Array.isArray( shapes ) ) { - }, + for ( var i = 0, l = shapes.length; i < l; i ++ ) { - getValueSize: function () { + var shape = shapes[ i ]; - return this.values.length / this.times.length; + data.shapes.push( shape.uuid ); - }, + } - // move all keyframes either forwards or backwards in time - shift: function ( timeOffset ) { + } else { - if ( timeOffset !== 0.0 ) { + data.shapes.push( shapes.uuid ); - var times = this.times; + } - for ( var i = 0, n = times.length; i !== n; ++ i ) { + return data; - times[ i ] += timeOffset; + } - } + function EdgesGeometry( geometry, thresholdAngle ) { - } + BufferGeometry.call( this ); - return this; + this.type = 'EdgesGeometry'; - }, + this.parameters = { + thresholdAngle: thresholdAngle + }; - // scale all keyframe times by a factor (useful for frame <-> seconds conversions) - scale: function ( timeScale ) { + thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1; - if ( timeScale !== 1.0 ) { + // buffer - var times = this.times; + var vertices = []; - for ( var i = 0, n = times.length; i !== n; ++ i ) { + // helper variables - times[ i ] *= timeScale; + var thresholdDot = Math.cos( MathUtils.DEG2RAD * thresholdAngle ); + var edge = [ 0, 0 ], edges = {}; + var edge1, edge2, key; + var keys = [ 'a', 'b', 'c' ]; - } + // prepare source geometry - } + var geometry2; - return this; + if ( geometry.isBufferGeometry ) { - }, + geometry2 = new Geometry(); + geometry2.fromBufferGeometry( geometry ); - // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. - // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values - trim: function ( startTime, endTime ) { + } else { - var times = this.times, - nKeys = times.length, - from = 0, - to = nKeys - 1; + geometry2 = geometry.clone(); - while ( from !== nKeys && times[ from ] < startTime ) { + } - ++ from; + geometry2.mergeVertices(); + geometry2.computeFaceNormals(); - } + var sourceVertices = geometry2.vertices; + var faces = geometry2.faces; - while ( to !== - 1 && times[ to ] > endTime ) { + // now create a data structure where each entry represents an edge with its adjoining faces - -- to; + for ( var i = 0, l = faces.length; i < l; i ++ ) { - } + var face = faces[ i ]; - ++ to; // inclusive -> exclusive bound + for ( var j = 0; j < 3; j ++ ) { - if ( from !== 0 || to !== nKeys ) { + edge1 = face[ keys[ j ] ]; + edge2 = face[ keys[ ( j + 1 ) % 3 ] ]; + edge[ 0 ] = Math.min( edge1, edge2 ); + edge[ 1 ] = Math.max( edge1, edge2 ); - // empty tracks are forbidden, so keep at least one keyframe - if ( from >= to ) to = Math.max( to, 1 ), from = to - 1; + key = edge[ 0 ] + ',' + edge[ 1 ]; - var stride = this.getValueSize(); - this.times = AnimationUtils.arraySlice( times, from, to ); - this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); + if ( edges[ key ] === undefined ) { - } + edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined }; - return this; + } else { - }, + edges[ key ].face2 = i; - // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable - validate: function () { + } - var valid = true; + } - var valueSize = this.getValueSize(); - if ( valueSize - Math.floor( valueSize ) !== 0 ) { + } - console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); - valid = false; + // generate vertices - } + for ( key in edges ) { - var times = this.times, - values = this.values, + var e = edges[ key ]; - nKeys = times.length; + // an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree. - if ( nKeys === 0 ) { + if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) { - console.error( 'THREE.KeyframeTrack: Track is empty.', this ); - valid = false; + var vertex = sourceVertices[ e.index1 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); + + vertex = sourceVertices[ e.index2 ]; + vertices.push( vertex.x, vertex.y, vertex.z ); } - var prevTime = null; + } - for ( var i = 0; i !== nKeys; i ++ ) { + // build geometry - var currTime = times[ i ]; + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - if ( typeof currTime === 'number' && isNaN( currTime ) ) { + } - console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); - valid = false; - break; + EdgesGeometry.prototype = Object.create( BufferGeometry.prototype ); + EdgesGeometry.prototype.constructor = EdgesGeometry; - } + // CylinderGeometry - if ( prevTime !== null && prevTime > currTime ) { + function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); - valid = false; - break; + Geometry.call( this ); - } + this.type = 'CylinderGeometry'; - prevTime = currTime; + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - } + this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) ); + this.mergeVertices(); - if ( values !== undefined ) { + } - if ( AnimationUtils.isTypedArray( values ) ) { + CylinderGeometry.prototype = Object.create( Geometry.prototype ); + CylinderGeometry.prototype.constructor = CylinderGeometry; - for ( var i = 0, n = values.length; i !== n; ++ i ) { + // CylinderBufferGeometry - var value = values[ i ]; + function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - if ( isNaN( value ) ) { + BufferGeometry.call( this ); - console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); - valid = false; - break; + this.type = 'CylinderBufferGeometry'; - } + this.parameters = { + radiusTop: radiusTop, + radiusBottom: radiusBottom, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - } + var scope = this; - } + radiusTop = radiusTop !== undefined ? radiusTop : 1; + radiusBottom = radiusBottom !== undefined ? radiusBottom : 1; + height = height || 1; - } + radialSegments = Math.floor( radialSegments ) || 8; + heightSegments = Math.floor( heightSegments ) || 1; - return valid; + openEnded = openEnded !== undefined ? openEnded : false; + thetaStart = thetaStart !== undefined ? thetaStart : 0.0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - }, + // buffers - // removes equivalent sequential keys as common in morph target sequences - // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) - optimize: function () { + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - var times = this.times, - values = this.values, - stride = this.getValueSize(), + // helper variables - smoothInterpolation = this.getInterpolation() === InterpolateSmooth, + var index = 0; + var indexArray = []; + var halfHeight = height / 2; + var groupStart = 0; - writeIndex = 1, - lastIndex = times.length - 1; + // generate geometry - for ( var i = 1; i < lastIndex; ++ i ) { + generateTorso(); - var keep = false; + if ( openEnded === false ) { - var time = times[ i ]; - var timeNext = times[ i + 1 ]; + if ( radiusTop > 0 ) { generateCap( true ); } + if ( radiusBottom > 0 ) { generateCap( false ); } - // remove adjacent keyframes scheduled at the same time + } - if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { + // build geometry - if ( ! smoothInterpolation ) { + this.setIndex( indices ); + this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - // remove unnecessary keyframes same as their neighbors + function generateTorso() { - var offset = i * stride, - offsetP = offset - stride, - offsetN = offset + stride; + var normal = new Vector3(); + var vertex = new Vector3(); - for ( var j = 0; j !== stride; ++ j ) { + var groupCount = 0; - var value = values[ offset + j ]; + // this will be used to calculate the normal + var slope = ( radiusBottom - radiusTop ) / height; - if ( value !== values[ offsetP + j ] || - value !== values[ offsetN + j ] ) { + // generate vertices, normals and uvs - keep = true; - break; + for ( var y = 0; y <= heightSegments; y ++ ) { - } + var indexRow = []; - } + var v = y / heightSegments; - } else { + // calculate the radius of the current row - keep = true; + var radius = v * ( radiusBottom - radiusTop ) + radiusTop; - } + for ( var x = 0; x <= radialSegments; x ++ ) { - } + var u = x / radialSegments; - // in-place compaction + var theta = u * thetaLength + thetaStart; - if ( keep ) { + var sinTheta = Math.sin( theta ); + var cosTheta = Math.cos( theta ); - if ( i !== writeIndex ) { + // vertex - times[ writeIndex ] = times[ i ]; + vertex.x = radius * sinTheta; + vertex.y = - v * height + halfHeight; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); - var readOffset = i * stride, - writeOffset = writeIndex * stride; + // normal - for ( var j = 0; j !== stride; ++ j ) { + normal.set( sinTheta, slope, cosTheta ).normalize(); + normals.push( normal.x, normal.y, normal.z ); - values[ writeOffset + j ] = values[ readOffset + j ]; + // uv - } + uvs.push( u, 1 - v ); - } + // save index of vertex in respective row - ++ writeIndex; + indexRow.push( index ++ ); } + // now save vertices of the row in our index array + + indexArray.push( indexRow ); + } - // flush last keyframe (compaction looks ahead) + // generate indices - if ( lastIndex > 0 ) { + for ( var x$1 = 0; x$1 < radialSegments; x$1 ++ ) { - times[ writeIndex ] = times[ lastIndex ]; + for ( var y$1 = 0; y$1 < heightSegments; y$1 ++ ) { - for ( var readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { + // we use the index array to access the correct indices - values[ writeOffset + j ] = values[ readOffset + j ]; + var a = indexArray[ y$1 ][ x$1 ]; + var b = indexArray[ y$1 + 1 ][ x$1 ]; + var c = indexArray[ y$1 + 1 ][ x$1 + 1 ]; + var d = indexArray[ y$1 ][ x$1 + 1 ]; - } + // faces - ++ writeIndex; + indices.push( a, b, d ); + indices.push( b, c, d ); - } + // update group counter - if ( writeIndex !== times.length ) { + groupCount += 6; - this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); - this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); + } } - return this; + // add a group to the geometry. this will ensure multi material support - } + scope.addGroup( groupStart, groupCount, 0 ); - } ); + // calculate new start value for groups - /** - * - * A Track of Boolean keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + groupStart += groupCount; - function BooleanKeyframeTrack( name, times, values ) { + } - KeyframeTrack.call( this, name, times, values ); + function generateCap( top ) { - } + var centerIndexStart, centerIndexEnd; - BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + var uv = new Vector2(); + var vertex = new Vector3(); - constructor: BooleanKeyframeTrack, + var groupCount = 0; - ValueTypeName: 'bool', - ValueBufferType: Array, + var radius = ( top === true ) ? radiusTop : radiusBottom; + var sign = ( top === true ) ? 1 : - 1; - DefaultInterpolation: InterpolateDiscrete, + // save the index of the first center vertex + centerIndexStart = index; - InterpolantFactoryMethodLinear: undefined, - InterpolantFactoryMethodSmooth: undefined + // 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 - // Note: Actually this track could have a optimized / compressed - // representation of a single value and a custom interpolant that - // computes "firstValue ^ isOdd( index )". + for ( var x = 1; x <= radialSegments; x ++ ) { - } ); + // vertex - /** - * - * A Track of keyframe values that represent color. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + vertices.push( 0, halfHeight * sign, 0 ); - function ColorKeyframeTrack( name, times, values, interpolation ) { + // normal - KeyframeTrack.call( this, name, times, values, interpolation ); + normals.push( 0, sign, 0 ); - } + // uv - ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + uvs.push( 0.5, 0.5 ); - constructor: ColorKeyframeTrack, + // increase index - ValueTypeName: 'color' + index ++; - // ValueBufferType is inherited + } - // DefaultInterpolation is inherited + // save the index of the last center vertex - // Note: Very basic implementation and nothing special yet. - // However, this is the place for color space parameterization. + centerIndexEnd = index; - } ); + // now we generate the surrounding vertices, normals and uvs - /** - * - * A Track of numeric keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + for ( var x$1 = 0; x$1 <= radialSegments; x$1 ++ ) { - function NumberKeyframeTrack( name, times, values, interpolation ) { + var u = x$1 / radialSegments; + var theta = u * thetaLength + thetaStart; - KeyframeTrack.call( this, name, times, values, interpolation ); + var cosTheta = Math.cos( theta ); + var sinTheta = Math.sin( theta ); - } + // vertex - NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + vertex.x = radius * sinTheta; + vertex.y = halfHeight * sign; + vertex.z = radius * cosTheta; + vertices.push( vertex.x, vertex.y, vertex.z ); - constructor: NumberKeyframeTrack, + // normal - ValueTypeName: 'number' + normals.push( 0, sign, 0 ); - // ValueBufferType is inherited + // uv - // DefaultInterpolation is inherited + uv.x = ( cosTheta * 0.5 ) + 0.5; + uv.y = ( sinTheta * 0.5 * sign ) + 0.5; + uvs.push( uv.x, uv.y ); - } ); + // increase index - /** - * Spherical linear unit quaternion interpolant. - * - * @author tschw - */ + index ++; - function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { + } - Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); + // generate indices - } + for ( var x$2 = 0; x$2 < radialSegments; x$2 ++ ) { - QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { + var c = centerIndexStart + x$2; + var i = centerIndexEnd + x$2; - constructor: QuaternionLinearInterpolant, + if ( top === true ) { - interpolate_: function ( i1, t0, t, t1 ) { + // face top - var result = this.resultBuffer, - values = this.sampleValues, - stride = this.valueSize, + indices.push( i, i + 1, c ); - offset = i1 * stride, + } else { - alpha = ( t - t0 ) / ( t1 - t0 ); + // face bottom - for ( var end = offset + stride; offset !== end; offset += 4 ) { + indices.push( i + 1, i, c ); - Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); + } - } + groupCount += 3; - return result; + } - } + // add a group to the geometry. this will ensure multi material support - } ); + scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); - /** - * - * A Track of quaternion keyframe values. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + // calculate new start value for groups - function QuaternionKeyframeTrack( name, times, values, interpolation ) { + groupStart += groupCount; - KeyframeTrack.call( this, name, times, values, interpolation ); + } } - QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry; - constructor: QuaternionKeyframeTrack, + // ConeGeometry - ValueTypeName: 'quaternion', + function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - // ValueBufferType is inherited + CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - DefaultInterpolation: InterpolateLinear, + this.type = 'ConeGeometry'; - InterpolantFactoryMethodLinear: function ( result ) { + this.parameters = { + radius: radius, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); + } - }, + ConeGeometry.prototype = Object.create( CylinderGeometry.prototype ); + ConeGeometry.prototype.constructor = ConeGeometry; - InterpolantFactoryMethodSmooth: undefined // not yet implemented + // ConeBufferGeometry - } ); + function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) { - /** - * - * A Track that interpolates Strings - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); - function StringKeyframeTrack( name, times, values, interpolation ) { + this.type = 'ConeBufferGeometry'; - KeyframeTrack.call( this, name, times, values, interpolation ); + this.parameters = { + radius: radius, + height: height, + radialSegments: radialSegments, + heightSegments: heightSegments, + openEnded: openEnded, + thetaStart: thetaStart, + thetaLength: thetaLength + }; } - StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { + ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype ); + ConeBufferGeometry.prototype.constructor = ConeBufferGeometry; - constructor: StringKeyframeTrack, + // CircleGeometry - ValueTypeName: 'string', - ValueBufferType: Array, + function CircleGeometry( radius, segments, thetaStart, thetaLength ) { - DefaultInterpolation: InterpolateDiscrete, + Geometry.call( this ); - InterpolantFactoryMethodLinear: undefined, + this.type = 'CircleGeometry'; - InterpolantFactoryMethodSmooth: undefined - - } ); - - /** - * - * A Track of vectored keyframe values. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ - - function VectorKeyframeTrack( name, times, values, interpolation ) { + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - KeyframeTrack.call( this, name, times, values, interpolation ); + this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) ); + this.mergeVertices(); } - VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - - constructor: VectorKeyframeTrack, - - ValueTypeName: 'vector' - - // ValueBufferType is inherited - - // DefaultInterpolation is inherited - - } ); - - /** - * - * Reusable set of Tracks that represent an animation. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - */ - - function AnimationClip( name, duration, tracks ) { - - this.name = name; - this.tracks = tracks; - this.duration = ( duration !== undefined ) ? duration : - 1; - - this.uuid = _Math.generateUUID(); - - // this means it should figure out its duration by scanning the tracks - if ( this.duration < 0 ) { + CircleGeometry.prototype = Object.create( Geometry.prototype ); + CircleGeometry.prototype.constructor = CircleGeometry; - this.resetDuration(); + // CircleBufferGeometry - } + function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) { - } + BufferGeometry.call( this ); - function getTrackTypeForValueTypeName( typeName ) { + this.type = 'CircleBufferGeometry'; - switch ( typeName.toLowerCase() ) { + this.parameters = { + radius: radius, + segments: segments, + thetaStart: thetaStart, + thetaLength: thetaLength + }; - case 'scalar': - case 'double': - case 'float': - case 'number': - case 'integer': + radius = radius || 1; + segments = segments !== undefined ? Math.max( 3, segments ) : 8; - return NumberKeyframeTrack; + thetaStart = thetaStart !== undefined ? thetaStart : 0; + thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; - case 'vector': - case 'vector2': - case 'vector3': - case 'vector4': + // buffers - return VectorKeyframeTrack; + var indices = []; + var vertices = []; + var normals = []; + var uvs = []; - case 'color': + // helper variables - return ColorKeyframeTrack; + var vertex = new Vector3(); + var uv = new Vector2(); - case 'quaternion': + // center point - return QuaternionKeyframeTrack; + vertices.push( 0, 0, 0 ); + normals.push( 0, 0, 1 ); + uvs.push( 0.5, 0.5 ); - case 'bool': - case 'boolean': + for ( var s = 0, i = 3; s <= segments; s ++, i += 3 ) { - return BooleanKeyframeTrack; + var segment = thetaStart + s / segments * thetaLength; - case 'string': + // vertex - return StringKeyframeTrack; + vertex.x = radius * Math.cos( segment ); + vertex.y = radius * Math.sin( segment ); - } + vertices.push( vertex.x, vertex.y, vertex.z ); - throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); + // normal - } + normals.push( 0, 0, 1 ); - function parseKeyframeTrack( json ) { + // uvs - if ( json.type === undefined ) { + uv.x = ( vertices[ i ] / radius + 1 ) / 2; + uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; - throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); + uvs.push( uv.x, uv.y ); } - var trackType = getTrackTypeForValueTypeName( json.type ); - - if ( json.times === undefined ) { - - var times = [], values = []; + // indices - AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); + for ( var i$1 = 1; i$1 <= segments; i$1 ++ ) { - json.times = times; - json.values = values; + indices.push( i$1, i$1 + 1, 0 ); } - // 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 ); + // 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 ) ); } - Object.assign( AnimationClip, { - - parse: function ( json ) { - - var tracks = [], - jsonTracks = json.tracks, - frameTime = 1.0 / ( json.fps || 1.0 ); - - for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { - - tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); - - } - - return new AnimationClip( json.name, json.duration, tracks ); + CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype ); + CircleBufferGeometry.prototype.constructor = CircleBufferGeometry; - }, + var Geometries = /*#__PURE__*/Object.freeze({ + __proto__: null, + WireframeGeometry: WireframeGeometry, + ParametricGeometry: ParametricGeometry, + ParametricBufferGeometry: ParametricBufferGeometry, + TetrahedronGeometry: TetrahedronGeometry, + TetrahedronBufferGeometry: TetrahedronBufferGeometry, + OctahedronGeometry: OctahedronGeometry, + OctahedronBufferGeometry: OctahedronBufferGeometry, + IcosahedronGeometry: IcosahedronGeometry, + IcosahedronBufferGeometry: IcosahedronBufferGeometry, + DodecahedronGeometry: DodecahedronGeometry, + DodecahedronBufferGeometry: DodecahedronBufferGeometry, + PolyhedronGeometry: PolyhedronGeometry, + PolyhedronBufferGeometry: PolyhedronBufferGeometry, + TubeGeometry: TubeGeometry, + TubeBufferGeometry: TubeBufferGeometry, + TorusKnotGeometry: TorusKnotGeometry, + TorusKnotBufferGeometry: TorusKnotBufferGeometry, + TorusGeometry: TorusGeometry, + TorusBufferGeometry: TorusBufferGeometry, + TextGeometry: TextGeometry, + TextBufferGeometry: TextBufferGeometry, + SphereGeometry: SphereGeometry, + SphereBufferGeometry: SphereBufferGeometry, + RingGeometry: RingGeometry, + RingBufferGeometry: RingBufferGeometry, + PlaneGeometry: PlaneGeometry, + PlaneBufferGeometry: PlaneBufferGeometry, + LatheGeometry: LatheGeometry, + LatheBufferGeometry: LatheBufferGeometry, + ShapeGeometry: ShapeGeometry, + ShapeBufferGeometry: ShapeBufferGeometry, + ExtrudeGeometry: ExtrudeGeometry, + ExtrudeBufferGeometry: ExtrudeBufferGeometry, + EdgesGeometry: EdgesGeometry, + ConeGeometry: ConeGeometry, + ConeBufferGeometry: ConeBufferGeometry, + CylinderGeometry: CylinderGeometry, + CylinderBufferGeometry: CylinderBufferGeometry, + CircleGeometry: CircleGeometry, + CircleBufferGeometry: CircleBufferGeometry, + BoxGeometry: BoxGeometry, + BoxBufferGeometry: BoxBufferGeometry + }); - toJSON: function ( clip ) { + /** + * parameters = { + * color: + * } + */ - var tracks = [], - clipTracks = clip.tracks; + function ShadowMaterial( parameters ) { - var json = { + Material.call( this ); - 'name': clip.name, - 'duration': clip.duration, - 'tracks': tracks, - 'uuid': clip.uuid + this.type = 'ShadowMaterial'; - }; + this.color = new Color( 0x000000 ); + this.transparent = true; - for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { + this.setValues( parameters ); - tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); + } - } + ShadowMaterial.prototype = Object.create( Material.prototype ); + ShadowMaterial.prototype.constructor = ShadowMaterial; - return json; + ShadowMaterial.prototype.isShadowMaterial = true; - }, + ShadowMaterial.prototype.copy = function ( source ) { - CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { + Material.prototype.copy.call( this, source ); - var numMorphTargets = morphTargetSequence.length; - var tracks = []; + this.color.copy( source.color ); - for ( var i = 0; i < numMorphTargets; i ++ ) { + return this; - var times = []; - var values = []; + }; - times.push( - ( i + numMorphTargets - 1 ) % numMorphTargets, - i, - ( i + 1 ) % numMorphTargets ); + function RawShaderMaterial( parameters ) { - values.push( 0, 1, 0 ); + ShaderMaterial.call( this, parameters ); - var order = AnimationUtils.getKeyframeOrder( times ); - times = AnimationUtils.sortedArray( times, 1, order ); - values = AnimationUtils.sortedArray( values, 1, order ); + this.type = 'RawShaderMaterial'; - // 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 ] ); + RawShaderMaterial.prototype = Object.create( ShaderMaterial.prototype ); + RawShaderMaterial.prototype.constructor = RawShaderMaterial; - } + RawShaderMaterial.prototype.isRawShaderMaterial = true; - tracks.push( - new NumberKeyframeTrack( - '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', - times, values - ).scale( 1.0 / fps ) ); + /** + * 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: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ - } + function MeshStandardMaterial( parameters ) { - return new AnimationClip( name, - 1, tracks ); + Material.call( this ); - }, + this.defines = { 'STANDARD': '' }; - findByName: function ( objectOrClipArray, name ) { + this.type = 'MeshStandardMaterial'; - var clipArray = objectOrClipArray; + this.color = new Color( 0xffffff ); // diffuse + this.roughness = 1.0; + this.metalness = 0.0; - if ( ! Array.isArray( objectOrClipArray ) ) { + this.map = null; - var o = objectOrClipArray; - clipArray = o.geometry && o.geometry.animations || o.animations; + this.lightMap = null; + this.lightMapIntensity = 1.0; - } + this.aoMap = null; + this.aoMapIntensity = 1.0; - for ( var i = 0; i < clipArray.length; i ++ ) { + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - if ( clipArray[ i ].name === name ) { + this.bumpMap = null; + this.bumpScale = 1; - return clipArray[ i ]; + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - } + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - } + this.roughnessMap = null; - return null; + this.metalnessMap = null; - }, + this.alphaMap = null; - CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { + this.envMap = null; + this.envMapIntensity = 1.0; - var animationToMorphTargets = {}; + this.refractionRatio = 0.98; - // tested with https://regex101.com/ on trick sequences - // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 - var pattern = /^([\w-]*?)([\d]+)$/; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - // sort morph target names into animation groups based - // patterns like Walk_001, Walk_002, Run_001, Run_002 - for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - var morphTarget = morphTargets[ i ]; - var parts = morphTarget.name.match( pattern ); + this.vertexTangents = false; - if ( parts && parts.length > 1 ) { + this.setValues( parameters ); - var name = parts[ 1 ]; + } - var animationMorphTargets = animationToMorphTargets[ name ]; - if ( ! animationMorphTargets ) { + MeshStandardMaterial.prototype = Object.create( Material.prototype ); + MeshStandardMaterial.prototype.constructor = MeshStandardMaterial; - animationToMorphTargets[ name ] = animationMorphTargets = []; + MeshStandardMaterial.prototype.isMeshStandardMaterial = true; - } + MeshStandardMaterial.prototype.copy = function ( source ) { - animationMorphTargets.push( morphTarget ); + Material.prototype.copy.call( this, source ); - } + this.defines = { 'STANDARD': '' }; - } + this.color.copy( source.color ); + this.roughness = source.roughness; + this.metalness = source.metalness; - var clips = []; + this.map = source.map; - for ( var name in animationToMorphTargets ) { + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - clips.push( AnimationClip.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - } + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - return clips; + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - }, + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - // parse the animation.hierarchy format - parseAnimation: function ( animation, bones ) { + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - if ( ! animation ) { + this.roughnessMap = source.roughnessMap; - console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); - return null; + this.metalnessMap = source.metalnessMap; - } + this.alphaMap = source.alphaMap; - var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { + this.envMap = source.envMap; + this.envMapIntensity = source.envMapIntensity; - // only return track if there are actually keys. - if ( animationKeys.length !== 0 ) { + this.refractionRatio = source.refractionRatio; - var times = []; - var values = []; + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - // empty keys are filtered out, so check again - if ( times.length !== 0 ) { + this.vertexTangents = source.vertexTangents; - destTracks.push( new trackType( trackName, times, values ) ); + return this; - } + }; - } + /** + * parameters = { + * clearcoat: , + * clearcoatMap: new THREE.Texture( ), + * clearcoatRoughness: , + * clearcoatRoughnessMap: new THREE.Texture( ), + * clearcoatNormalScale: , + * clearcoatNormalMap: new THREE.Texture( ), + * + * reflectivity: , + * + * sheen: , + * + * transmission: , + * transmissionMap: new THREE.Texture( ) + * } + */ - }; + function MeshPhysicalMaterial( parameters ) { - var tracks = []; + MeshStandardMaterial.call( this ); - var clipName = animation.name || 'default'; - // automatic length determination in AnimationClip. - var duration = animation.length || - 1; - var fps = animation.fps || 30; + this.defines = { - var hierarchyTracks = animation.hierarchy || []; + 'STANDARD': '', + 'PHYSICAL': '' - for ( var h = 0; h < hierarchyTracks.length; h ++ ) { + }; - var animationKeys = hierarchyTracks[ h ].keys; + this.type = 'MeshPhysicalMaterial'; - // skip empty tracks - if ( ! animationKeys || animationKeys.length === 0 ) continue; + this.clearcoat = 0.0; + this.clearcoatMap = null; + this.clearcoatRoughness = 0.0; + this.clearcoatRoughnessMap = null; + this.clearcoatNormalScale = new Vector2( 1, 1 ); + this.clearcoatNormalMap = null; - // process morph targets - if ( animationKeys[ 0 ].morphTargets ) { + this.reflectivity = 0.5; // maps to F0 = 0.04 - // figure out all morph targets used in this track - var morphTargetNames = {}; + this.sheen = null; // null will disable sheen bsdf - for ( var k = 0; k < animationKeys.length; k ++ ) { + this.transmission = 0.0; + this.transmissionMap = null; - if ( animationKeys[ k ].morphTargets ) { + this.setValues( parameters ); - for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { + } - morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; + MeshPhysicalMaterial.prototype = Object.create( MeshStandardMaterial.prototype ); + MeshPhysicalMaterial.prototype.constructor = MeshPhysicalMaterial; - } + MeshPhysicalMaterial.prototype.isMeshPhysicalMaterial = true; - } + MeshPhysicalMaterial.prototype.copy = function ( source ) { - } + MeshStandardMaterial.prototype.copy.call( this, source ); - // create a track for each morph target with all zero - // morphTargetInfluences except for the keys in which - // the morphTarget is named. - for ( var morphTargetName in morphTargetNames ) { + this.defines = { - var times = []; - var values = []; + 'STANDARD': '', + 'PHYSICAL': '' - for ( var m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { + }; - var animationKey = animationKeys[ k ]; + 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 ); - times.push( animationKey.time ); - values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); + this.reflectivity = source.reflectivity; - } + if ( source.sheen ) { - tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); + this.sheen = ( this.sheen || new Color() ).copy( source.sheen ); - } + } else { - duration = morphTargetNames.length * ( fps || 1.0 ); + this.sheen = null; - } else { + } - // ...assume skeletal animation + this.transmission = source.transmission; + this.transmissionMap = source.transmissionMap; - var boneName = '.bones[' + bones[ h ].name + ']'; + return this; - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.position', - animationKeys, 'pos', tracks ); + }; - addNonemptyTrack( - QuaternionKeyframeTrack, boneName + '.quaternion', - animationKeys, 'rot', tracks ); - - addNonemptyTrack( - VectorKeyframeTrack, boneName + '.scale', - animationKeys, 'scl', tracks ); - - } - - } + /** + * 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: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ - if ( tracks.length === 0 ) { + function MeshPhongMaterial( parameters ) { - return null; + Material.call( this ); - } + this.type = 'MeshPhongMaterial'; - var clip = new AnimationClip( clipName, duration, tracks ); + this.color = new Color( 0xffffff ); // diffuse + this.specular = new Color( 0x111111 ); + this.shininess = 30; - return clip; + this.map = null; - } + this.lightMap = null; + this.lightMapIntensity = 1.0; - } ); + this.aoMap = null; + this.aoMapIntensity = 1.0; - Object.assign( AnimationClip.prototype, { + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - resetDuration: function () { + this.bumpMap = null; + this.bumpScale = 1; - var tracks = this.tracks, duration = 0; + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - for ( var i = 0, n = tracks.length; i !== n; ++ i ) { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - var track = this.tracks[ i ]; + this.specularMap = null; - duration = Math.max( duration, track.times[ track.times.length - 1 ] ); + this.alphaMap = null; - } + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - this.duration = duration; + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - return this; + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - }, + this.setValues( parameters ); - trim: function () { + } - for ( var i = 0; i < this.tracks.length; i ++ ) { + MeshPhongMaterial.prototype = Object.create( Material.prototype ); + MeshPhongMaterial.prototype.constructor = MeshPhongMaterial; - this.tracks[ i ].trim( 0, this.duration ); + MeshPhongMaterial.prototype.isMeshPhongMaterial = true; - } + MeshPhongMaterial.prototype.copy = function ( source ) { - return this; + Material.prototype.copy.call( this, source ); - }, + this.color.copy( source.color ); + this.specular.copy( source.specular ); + this.shininess = source.shininess; - validate: function () { + this.map = source.map; - var valid = true; + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - for ( var i = 0; i < this.tracks.length; i ++ ) { + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - valid = valid && this.tracks[ i ].validate(); + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - } + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - return valid; + 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; - optimize: function () { + this.specularMap = source.specularMap; - for ( var i = 0; i < this.tracks.length; i ++ ) { + this.alphaMap = source.alphaMap; - this.tracks[ i ].optimize(); + 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; + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - } + return this; - } ); + }; /** - * @author mrdoob / http://mrdoob.com/ + * 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: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } */ - var Cache = { + function MeshToonMaterial( parameters ) { - enabled: false, + Material.call( this ); - files: {}, + this.defines = { 'TOON': '' }; - add: function ( key, file ) { + this.type = 'MeshToonMaterial'; - if ( this.enabled === false ) return; + this.color = new Color( 0xffffff ); - // console.log( 'THREE.Cache', 'Adding key:', key ); + this.map = null; + this.gradientMap = null; - this.files[ key ] = file; + this.lightMap = null; + this.lightMapIntensity = 1.0; - }, + this.aoMap = null; + this.aoMapIntensity = 1.0; - get: function ( key ) { + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - if ( this.enabled === false ) return; + this.bumpMap = null; + this.bumpScale = 1; - // console.log( 'THREE.Cache', 'Checking key:', key ); + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - return this.files[ key ]; + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - }, + this.alphaMap = null; - remove: function ( key ) { + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - delete this.files[ key ]; + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - }, + this.setValues( parameters ); - clear: function () { + } - this.files = {}; + MeshToonMaterial.prototype = Object.create( Material.prototype ); + MeshToonMaterial.prototype.constructor = MeshToonMaterial; - } + MeshToonMaterial.prototype.isMeshToonMaterial = true; - }; + MeshToonMaterial.prototype.copy = function ( source ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + Material.prototype.copy.call( this, source ); - function LoadingManager( onLoad, onProgress, onError ) { + this.color.copy( source.color ); - var scope = this; + this.map = source.map; + this.gradientMap = source.gradientMap; - var isLoading = false; - var itemsLoaded = 0; - var itemsTotal = 0; - var urlModifier = undefined; + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - // Refer to #5689 for the reason why we don't set .onStart - // in the constructor + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - this.itemStart = function ( url ) { + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - itemsTotal ++; + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - if ( isLoading === false ) { + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - if ( scope.onStart !== undefined ) { + this.alphaMap = source.alphaMap; - scope.onStart( url, itemsLoaded, itemsTotal ); + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - } + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - } + return this; - isLoading = true; + }; - }; + /** + * parameters = { + * opacity: , + * + * bumpMap: new THREE.Texture( ), + * bumpScale: , + * + * normalMap: new THREE.Texture( ), + * normalMapType: THREE.TangentSpaceNormalMap, + * normalScale: , + * + * displacementMap: new THREE.Texture( ), + * displacementScale: , + * displacementBias: , + * + * wireframe: , + * wireframeLinewidth: + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ - this.itemEnd = function ( url ) { + function MeshNormalMaterial( parameters ) { - itemsLoaded ++; + Material.call( this ); - if ( scope.onProgress !== undefined ) { + this.type = 'MeshNormalMaterial'; - scope.onProgress( url, itemsLoaded, itemsTotal ); + this.bumpMap = null; + this.bumpScale = 1; - } + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - if ( itemsLoaded === itemsTotal ) { + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - isLoading = false; + this.wireframe = false; + this.wireframeLinewidth = 1; - if ( scope.onLoad !== undefined ) { + this.fog = false; - scope.onLoad(); + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - } + this.setValues( parameters ); - } + } - }; + MeshNormalMaterial.prototype = Object.create( Material.prototype ); + MeshNormalMaterial.prototype.constructor = MeshNormalMaterial; - this.itemError = function ( url ) { + MeshNormalMaterial.prototype.isMeshNormalMaterial = true; - if ( scope.onError !== undefined ) { + MeshNormalMaterial.prototype.copy = function ( source ) { - scope.onError( url ); + Material.prototype.copy.call( this, source ); - } + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - }; + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - this.resolveURL = function ( url ) { + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - if ( urlModifier ) { + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; - return urlModifier( url ); + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - } + return this; - return url; + }; - }; + /** + * 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: , + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ - this.setURLModifier = function ( transform ) { + function MeshLambertMaterial( parameters ) { - urlModifier = transform; - return this; + Material.call( this ); - }; + this.type = 'MeshLambertMaterial'; - } + this.color = new Color( 0xffffff ); // diffuse - var DefaultLoadingManager = new LoadingManager(); + this.map = null; - /** - * @author mrdoob / http://mrdoob.com/ - */ + this.lightMap = null; + this.lightMapIntensity = 1.0; - var loading = {}; + this.aoMap = null; + this.aoMapIntensity = 1.0; - function FileLoader( manager ) { + this.emissive = new Color( 0x000000 ); + this.emissiveIntensity = 1.0; + this.emissiveMap = null; - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.specularMap = null; - } + this.alphaMap = null; - Object.assign( FileLoader.prototype, { + this.envMap = null; + this.combine = MultiplyOperation; + this.reflectivity = 1; + this.refractionRatio = 0.98; - load: function ( url, onLoad, onProgress, onError ) { + this.wireframe = false; + this.wireframeLinewidth = 1; + this.wireframeLinecap = 'round'; + this.wireframeLinejoin = 'round'; - if ( url === undefined ) url = ''; + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - if ( this.path !== undefined ) url = this.path + url; + this.setValues( parameters ); - url = this.manager.resolveURL( url ); + } - var scope = this; + MeshLambertMaterial.prototype = Object.create( Material.prototype ); + MeshLambertMaterial.prototype.constructor = MeshLambertMaterial; - var cached = Cache.get( url ); + MeshLambertMaterial.prototype.isMeshLambertMaterial = true; - if ( cached !== undefined ) { + MeshLambertMaterial.prototype.copy = function ( source ) { - scope.manager.itemStart( url ); + Material.prototype.copy.call( this, source ); - setTimeout( function () { + this.color.copy( source.color ); - if ( onLoad ) onLoad( cached ); + this.map = source.map; - scope.manager.itemEnd( url ); + this.lightMap = source.lightMap; + this.lightMapIntensity = source.lightMapIntensity; - }, 0 ); + this.aoMap = source.aoMap; + this.aoMapIntensity = source.aoMapIntensity; - return cached; + this.emissive.copy( source.emissive ); + this.emissiveMap = source.emissiveMap; + this.emissiveIntensity = source.emissiveIntensity; - } + this.specularMap = source.specularMap; - // Check if request is duplicate + this.alphaMap = source.alphaMap; - if ( loading[ url ] !== undefined ) { + this.envMap = source.envMap; + this.combine = source.combine; + this.reflectivity = source.reflectivity; + this.refractionRatio = source.refractionRatio; - loading[ url ].push( { + this.wireframe = source.wireframe; + this.wireframeLinewidth = source.wireframeLinewidth; + this.wireframeLinecap = source.wireframeLinecap; + this.wireframeLinejoin = source.wireframeLinejoin; - onLoad: onLoad, - onProgress: onProgress, - onError: onError + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - } ); + return this; - return; + }; - } - - // Check for data: URI - var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; - var dataUriRegexResult = url.match( dataUriRegex ); - - // Safari can not handle Data URIs through XMLHttpRequest so process manually - if ( dataUriRegexResult ) { + /** + * 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( ), + * + * skinning: , + * morphTargets: , + * morphNormals: + * } + */ - var mimeType = dataUriRegexResult[ 1 ]; - var isBase64 = !! dataUriRegexResult[ 2 ]; - var data = dataUriRegexResult[ 3 ]; + function MeshMatcapMaterial( parameters ) { - data = decodeURIComponent( data ); + Material.call( this ); - if ( isBase64 ) data = atob( data ); + this.defines = { 'MATCAP': '' }; - try { + this.type = 'MeshMatcapMaterial'; - var response; - var responseType = ( this.responseType || '' ).toLowerCase(); + this.color = new Color( 0xffffff ); // diffuse - switch ( responseType ) { + this.matcap = null; - case 'arraybuffer': - case 'blob': + this.map = null; - var view = new Uint8Array( data.length ); + this.bumpMap = null; + this.bumpScale = 1; - for ( var i = 0; i < data.length; i ++ ) { + this.normalMap = null; + this.normalMapType = TangentSpaceNormalMap; + this.normalScale = new Vector2( 1, 1 ); - view[ i ] = data.charCodeAt( i ); + this.displacementMap = null; + this.displacementScale = 1; + this.displacementBias = 0; - } + this.alphaMap = null; - if ( responseType === 'blob' ) { + this.skinning = false; + this.morphTargets = false; + this.morphNormals = false; - response = new Blob( [ view.buffer ], { type: mimeType } ); + this.setValues( parameters ); - } else { + } - response = view.buffer; + MeshMatcapMaterial.prototype = Object.create( Material.prototype ); + MeshMatcapMaterial.prototype.constructor = MeshMatcapMaterial; - } + MeshMatcapMaterial.prototype.isMeshMatcapMaterial = true; - break; + MeshMatcapMaterial.prototype.copy = function ( source ) { - case 'document': + Material.prototype.copy.call( this, source ); - var parser = new DOMParser(); - response = parser.parseFromString( data, mimeType ); + this.defines = { 'MATCAP': '' }; - break; + this.color.copy( source.color ); - case 'json': + this.matcap = source.matcap; - response = JSON.parse( data ); + this.map = source.map; - break; + this.bumpMap = source.bumpMap; + this.bumpScale = source.bumpScale; - default: // 'text' or other + this.normalMap = source.normalMap; + this.normalMapType = source.normalMapType; + this.normalScale.copy( source.normalScale ); - response = data; + this.displacementMap = source.displacementMap; + this.displacementScale = source.displacementScale; + this.displacementBias = source.displacementBias; - break; + this.alphaMap = source.alphaMap; - } + this.skinning = source.skinning; + this.morphTargets = source.morphTargets; + this.morphNormals = source.morphNormals; - // Wait for next browser tick like standard XMLHttpRequest event dispatching does - setTimeout( function () { + return this; - if ( onLoad ) onLoad( response ); + }; - scope.manager.itemEnd( url ); + /** + * parameters = { + * color: , + * opacity: , + * + * linewidth: , + * + * scale: , + * dashSize: , + * gapSize: + * } + */ - }, 0 ); + function LineDashedMaterial( parameters ) { - } catch ( error ) { + LineBasicMaterial.call( this ); - // Wait for next browser tick like standard XMLHttpRequest event dispatching does - setTimeout( function () { + this.type = 'LineDashedMaterial'; - if ( onError ) onError( error ); + this.scale = 1; + this.dashSize = 3; + this.gapSize = 1; - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + this.setValues( parameters ); - }, 0 ); + } - } + LineDashedMaterial.prototype = Object.create( LineBasicMaterial.prototype ); + LineDashedMaterial.prototype.constructor = LineDashedMaterial; - } else { + LineDashedMaterial.prototype.isLineDashedMaterial = true; - // Initialise array for duplicate requests + LineDashedMaterial.prototype.copy = function ( source ) { - loading[ url ] = []; + LineBasicMaterial.prototype.copy.call( this, source ); - loading[ url ].push( { + this.scale = source.scale; + this.dashSize = source.dashSize; + this.gapSize = source.gapSize; - onLoad: onLoad, - onProgress: onProgress, - onError: onError + return this; - } ); + }; - var request = new XMLHttpRequest(); + 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 + }); - request.open( 'GET', url, true ); + var AnimationUtils = { - request.addEventListener( 'load', function ( event ) { + // same as Array.prototype.slice, but also works on typed arrays + arraySlice: function ( array, from, to ) { - var response = this.response; + if ( AnimationUtils.isTypedArray( array ) ) { - Cache.add( url, response ); + // 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 ) ); - var callbacks = loading[ url ]; + } - delete loading[ url ]; + return array.slice( from, to ); - 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. + // converts an array to a specific type + convertArray: function ( array, type, forceClone ) { - if ( this.status === 0 ) console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); + if ( ! array || // let 'undefined' and 'null' pass + ! forceClone && array.constructor === type ) { return array; } - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { - var callback = callbacks[ i ]; - if ( callback.onLoad ) callback.onLoad( response ); + return new type( array ); // create typed array - } + } - scope.manager.itemEnd( url ); + return Array.prototype.slice.call( array ); // create Array - } else { + }, - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + isTypedArray: function ( object ) { - var callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( event ); + return ArrayBuffer.isView( object ) && + ! ( object instanceof DataView ); - } + }, - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + // returns an array by which times and values can be sorted + getKeyframeOrder: function ( times ) { - } + function compareTime( i, j ) { - }, false ); + return times[ i ] - times[ j ]; - request.addEventListener( 'progress', function ( event ) { + } - var callbacks = loading[ url ]; + var n = times.length; + var result = new Array( n ); + for ( var i = 0; i !== n; ++ i ) { result[ i ] = i; } - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + result.sort( compareTime ); - var callback = callbacks[ i ]; - if ( callback.onProgress ) callback.onProgress( event ); + return result; - } + }, - }, false ); + // uses the array previously returned by 'getKeyframeOrder' to sort data + sortedArray: function ( values, stride, order ) { - request.addEventListener( 'error', function ( event ) { + var nValues = values.length; + var result = new values.constructor( nValues ); - var callbacks = loading[ url ]; + for ( var i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { - delete loading[ url ]; + var srcOffset = order[ i ] * stride; - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + for ( var j = 0; j !== stride; ++ j ) { - var callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( event ); + result[ dstOffset ++ ] = values[ srcOffset + j ]; - } + } - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + } - }, false ); + return result; - request.addEventListener( 'abort', function ( event ) { + }, - var callbacks = loading[ url ]; + // function for parsing AOS keyframe formats + flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) { - delete loading[ url ]; + var i = 1, key = jsonKeys[ 0 ]; - for ( var i = 0, il = callbacks.length; i < il; i ++ ) { + while ( key !== undefined && key[ valuePropertyName ] === undefined ) { - var callback = callbacks[ i ]; - if ( callback.onError ) callback.onError( event ); + key = jsonKeys[ i ++ ]; - } + } - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + if ( key === undefined ) { return; } // no data - }, false ); + var value = key[ valuePropertyName ]; + if ( value === undefined ) { return; } // no data - if ( this.responseType !== undefined ) request.responseType = this.responseType; - if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials; + if ( Array.isArray( value ) ) { - if ( request.overrideMimeType ) request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); + do { - for ( var header in this.requestHeader ) { + value = key[ valuePropertyName ]; - request.setRequestHeader( header, this.requestHeader[ header ] ); + if ( value !== undefined ) { - } + times.push( key.time ); + values.push.apply( values, value ); // push all elements - request.send( null ); + } - } + key = jsonKeys[ i ++ ]; - scope.manager.itemStart( url ); + } while ( key !== undefined ); - return request; + } else if ( value.toArray !== undefined ) { - }, + // ...assume THREE.Math-ish - setPath: function ( value ) { + do { - this.path = value; - return this; + value = key[ valuePropertyName ]; - }, + if ( value !== undefined ) { - setResponseType: function ( value ) { + times.push( key.time ); + value.toArray( values, values.length ); - this.responseType = value; - return this; + } - }, + key = jsonKeys[ i ++ ]; - setWithCredentials: function ( value ) { + } while ( key !== undefined ); - this.withCredentials = value; - return this; + } else { - }, + // otherwise push as-is - setMimeType: function ( value ) { + do { - this.mimeType = value; - return this; + value = key[ valuePropertyName ]; - }, + if ( value !== undefined ) { - setRequestHeader: function ( value ) { + times.push( key.time ); + values.push( value ); - this.requestHeader = value; - return this; + } - } + key = jsonKeys[ i ++ ]; - } ); + } while ( key !== undefined ); - /** - * @author bhouston / http://clara.io/ - */ + } - function AnimationLoader( manager ) { + }, - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + subclip: function ( sourceClip, name, startFrame, endFrame, fps ) { - } + fps = fps || 30; - Object.assign( AnimationLoader.prototype, { + var clip = sourceClip.clone(); - load: function ( url, onLoad, onProgress, onError ) { + clip.name = name; - var scope = this; + var tracks = []; - var loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.load( url, function ( text ) { + for ( var i = 0; i < clip.tracks.length; ++ i ) { - onLoad( scope.parse( JSON.parse( text ) ) ); + var track = clip.tracks[ i ]; + var valueSize = track.getValueSize(); - }, onProgress, onError ); + var times = []; + var values = []; - }, + for ( var j = 0; j < track.times.length; ++ j ) { - parse: function ( json, onLoad ) { + var frame = track.times[ j ] * fps; - var animations = []; + if ( frame < startFrame || frame >= endFrame ) { continue; } - for ( var i = 0; i < json.length; i ++ ) { + times.push( track.times[ j ] ); - var clip = AnimationClip.parse( json[ i ] ); + for ( var k = 0; k < valueSize; ++ k ) { - animations.push( clip ); + values.push( track.values[ j * valueSize + k ] ); - } + } - onLoad( animations ); + } - }, + if ( times.length === 0 ) { continue; } - setPath: function ( value ) { + track.times = AnimationUtils.convertArray( times, track.times.constructor ); + track.values = AnimationUtils.convertArray( values, track.values.constructor ); - this.path = value; - return this; + tracks.push( track ); - } + } - } ); + clip.tracks = tracks; - /** - * @author mrdoob / http://mrdoob.com/ - * - * Abstract Base class to block based textures loader (dds, pvr, ...) - */ + // find minimum .times value across all tracks in the trimmed clip - function CompressedTextureLoader( manager ) { + var minStartTime = Infinity; - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + for ( var i$1 = 0; i$1 < clip.tracks.length; ++ i$1 ) { - // override in sub classes - this._parser = null; + if ( minStartTime > clip.tracks[ i$1 ].times[ 0 ] ) { - } + minStartTime = clip.tracks[ i$1 ].times[ 0 ]; - Object.assign( CompressedTextureLoader.prototype, { + } - load: function ( url, onLoad, onProgress, onError ) { + } - var scope = this; + // shift all tracks such that clip begins at t=0 - var images = []; + for ( var i$2 = 0; i$2 < clip.tracks.length; ++ i$2 ) { - var texture = new CompressedTexture(); - texture.image = images; + clip.tracks[ i$2 ].shift( - 1 * minStartTime ); - var loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setResponseType( 'arraybuffer' ); + } - function loadTexture( i ) { + clip.resetDuration(); - loader.load( url[ i ], function ( buffer ) { + return clip; - var texDatas = scope._parser( buffer, true ); + }, - images[ i ] = { - width: texDatas.width, - height: texDatas.height, - format: texDatas.format, - mipmaps: texDatas.mipmaps - }; + makeClipAdditive: function ( targetClip, referenceFrame, referenceClip, fps ) { - loaded += 1; + if ( referenceFrame === undefined ) { referenceFrame = 0; } + if ( referenceClip === undefined ) { referenceClip = targetClip; } + if ( fps === undefined || fps <= 0 ) { fps = 30; } - if ( loaded === 6 ) { + var numTracks = targetClip.tracks.length; + var referenceTime = referenceFrame / fps; - if ( texDatas.mipmapCount === 1 ) - texture.minFilter = LinearFilter; + // Make each track's values relative to the values at the reference frame + var loop = function ( i ) { - texture.format = texDatas.format; - texture.needsUpdate = true; + var referenceTrack = referenceClip.tracks[ i ]; + var referenceTrackType = referenceTrack.ValueTypeName; - if ( onLoad ) onLoad( texture ); + // Skip this track if it's non-numeric + if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) { return; } - } + // Find the track in the target clip whose name and type matches the reference track + var targetTrack = targetClip.tracks.find( function ( track ) { - }, onProgress, onError ); + return track.name === referenceTrack.name + && track.ValueTypeName === referenceTrackType; - } + } ); - if ( Array.isArray( url ) ) { + if ( targetTrack === undefined ) { return; } - var loaded = 0; + var valueSize = referenceTrack.getValueSize(); + var lastIndex = referenceTrack.times.length - 1; + var referenceValue = (void 0); - for ( var i = 0, il = url.length; i < il; ++ i ) { + // Find the value to subtract out of the track + if ( referenceTime <= referenceTrack.times[ 0 ] ) { - loadTexture( i ); + // Reference frame is earlier than the first keyframe, so just use the first keyframe + referenceValue = AnimationUtils.arraySlice( referenceTrack.values, 0, referenceTrack.valueSize ); - } + } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { - } else { + // Reference frame is after the last keyframe, so just use the last keyframe + var startIndex = lastIndex * valueSize; + referenceValue = AnimationUtils.arraySlice( referenceTrack.values, startIndex ); - // compressed cubemap texture stored in a single DDS file + } else { - loader.load( url, function ( buffer ) { + // Interpolate to the reference value + var interpolant = referenceTrack.createInterpolant(); + interpolant.evaluate( referenceTime ); + referenceValue = interpolant.resultBuffer; - var texDatas = scope._parser( buffer, true ); + } - if ( texDatas.isCubemap ) { + // Conjugate the quaternion + if ( referenceTrackType === 'quaternion' ) { - var faces = texDatas.mipmaps.length / texDatas.mipmapCount; + var referenceQuat = new Quaternion( + referenceValue[ 0 ], + referenceValue[ 1 ], + referenceValue[ 2 ], + referenceValue[ 3 ] + ).normalize().conjugate(); + referenceQuat.toArray( referenceValue ); - for ( var f = 0; f < faces; f ++ ) { + } - images[ f ] = { mipmaps: [] }; + // Subtract the reference value from all of the track values - for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { + var numTimes = targetTrack.times.length; + for ( var j = 0; j < numTimes; ++ j ) { - 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; + var valueStart = j * valueSize; - } + if ( referenceTrackType === 'quaternion' ) { - } + // Multiply the conjugate for quaternion track types + Quaternion.multiplyQuaternionsFlat( + targetTrack.values, + valueStart, + referenceValue, + 0, + targetTrack.values, + valueStart + ); } else { - texture.image.width = texDatas.width; - texture.image.height = texDatas.height; - texture.mipmaps = texDatas.mipmaps; - - } + // Subtract each value for all other numeric track types + for ( var k = 0; k < valueSize; ++ k ) { - if ( texDatas.mipmapCount === 1 ) { + targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; - texture.minFilter = LinearFilter; + } } - texture.format = texDatas.format; - texture.needsUpdate = true; - - if ( onLoad ) onLoad( texture ); - - }, onProgress, onError ); - - } + } - return texture; + }; - }, + for ( var i = 0; i < numTracks; ++ i ) loop( i ); - setPath: function ( value ) { + targetClip.blendMode = AdditiveAnimationBlendMode; - this.path = value; - return this; + return targetClip; } - } ); + }; /** - * @author Nikos M. / https://github.com/foo123/ + * 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 * - * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) */ - function DataTextureLoader( manager ) { + function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.parameterPositions = parameterPositions; + this._cachedIndex = 0; - // override in sub classes - this._parser = null; + this.resultBuffer = resultBuffer !== undefined ? + resultBuffer : new sampleValues.constructor( sampleSize ); + this.sampleValues = sampleValues; + this.valueSize = sampleSize; } - Object.assign( DataTextureLoader.prototype, { - - load: function ( url, onLoad, onProgress, onError ) { + Object.assign( Interpolant.prototype, { - var scope = this; + evaluate: function ( t ) { - var texture = new DataTexture(); + var pp = this.parameterPositions, + i1 = this._cachedIndex, - var loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setPath( this.path ); - loader.load( url, function ( buffer ) { + t1 = pp[ i1 ], + t0 = pp[ i1 - 1 ]; - var texData = scope._parser( buffer ); + validate_interval: { - if ( ! texData ) return; + seek: { - if ( texData.image !== undefined ) { + var right; - texture.image = texData.image; + linear_scan: { - } else if ( texData.data !== undefined ) { + //- See http://jsperf.com/comparison-to-undefined/3 + //- slower code: + //- + //- if ( t >= t1 || t1 === undefined ) { + forward_scan: if ( ! ( t < t1 ) ) { - texture.image.width = texData.width; - texture.image.height = texData.height; - texture.image.data = texData.data; + for ( var giveUpAt = i1 + 2; ; ) { - } + if ( t1 === undefined ) { - texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; - texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; + if ( t < t0 ) { break forward_scan; } - texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; - texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearMipMapLinearFilter; + // after end - texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t, t0 ); - if ( texData.format !== undefined ) { + } - texture.format = texData.format; + if ( i1 === giveUpAt ) { break; } // this loop - } - if ( texData.type !== undefined ) { + t0 = t1; + t1 = pp[ ++ i1 ]; - texture.type = texData.type; + if ( t < t1 ) { - } + // we have arrived at the sought interval + break seek; - if ( texData.mipmaps !== undefined ) { + } - texture.mipmaps = texData.mipmaps; + } - } + // prepare binary search on the right side of the index + right = pp.length; + break linear_scan; - if ( texData.mipmapCount === 1 ) { + } - texture.minFilter = LinearFilter; + //- slower code: + //- if ( t < t0 || t0 === undefined ) { + if ( ! ( t >= t0 ) ) { - } + // looping? - texture.needsUpdate = true; + var t1global = pp[ 1 ]; - if ( onLoad ) onLoad( texture, texData ); + if ( t < t1global ) { - }, onProgress, onError ); + i1 = 2; // + 1, using the scan for the details + t0 = t1global; + } - return texture; + // linear reverse scan - }, + for ( var giveUpAt$1 = i1 - 2; ; ) { - setPath: function ( value ) { + if ( t0 === undefined ) { - this.path = value; - return this; + // before start - } + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); - } ); + } - /** - * @author mrdoob / http://mrdoob.com/ - */ + if ( i1 === giveUpAt$1 ) { break; } // this loop + t1 = t0; + t0 = pp[ -- i1 - 1 ]; - function ImageLoader( manager ) { + if ( t >= t0 ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + // we have arrived at the sought interval + break seek; - } + } - Object.assign( ImageLoader.prototype, { + } - crossOrigin: 'anonymous', + // prepare binary search on the left side of the index + right = i1; + i1 = 0; + break linear_scan; - load: function ( url, onLoad, onProgress, onError ) { + } - if ( url === undefined ) url = ''; + // the interval is valid - if ( this.path !== undefined ) url = this.path + url; + break validate_interval; - url = this.manager.resolveURL( url ); + } // linear scan - var scope = this; + // binary search - var cached = Cache.get( url ); + while ( i1 < right ) { - if ( cached !== undefined ) { + var mid = ( i1 + right ) >>> 1; - scope.manager.itemStart( url ); + if ( t < pp[ mid ] ) { - setTimeout( function () { + right = mid; - if ( onLoad ) onLoad( cached ); + } else { - scope.manager.itemEnd( url ); + i1 = mid + 1; - }, 0 ); + } - return cached; + } - } + t1 = pp[ i1 ]; + t0 = pp[ i1 - 1 ]; - var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' ); + // check boundary cases, again - function onImageLoad() { + if ( t0 === undefined ) { - image.removeEventListener( 'load', onImageLoad, false ); - image.removeEventListener( 'error', onImageError, false ); + this._cachedIndex = 0; + return this.beforeStart_( 0, t, t1 ); - Cache.add( url, this ); + } - if ( onLoad ) onLoad( this ); + if ( t1 === undefined ) { - scope.manager.itemEnd( url ); + i1 = pp.length; + this._cachedIndex = i1; + return this.afterEnd_( i1 - 1, t0, t ); - } + } - function onImageError( event ) { + } // seek - image.removeEventListener( 'load', onImageLoad, false ); - image.removeEventListener( 'error', onImageError, false ); + this._cachedIndex = i1; - if ( onError ) onError( event ); + this.intervalChanged_( i1, t0, t1 ); - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + } // validate_interval - } + return this.interpolate_( i1, t0, t, t1 ); - image.addEventListener( 'load', onImageLoad, false ); - image.addEventListener( 'error', onImageError, false ); + }, - if ( url.substr( 0, 5 ) !== 'data:' ) { + settings: null, // optional, subclass-specific settings structure + // Note: The indirection allows central control of many interpolants. - if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; + // --- Protected interface - } + DefaultSettings_: {}, - scope.manager.itemStart( url ); + getSettings_: function () { - image.src = url; + return this.settings || this.DefaultSettings_; - return image; + }, + + copySampleValue_: function ( index ) { + + // copies a sample value to the result buffer + + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, + offset = index * stride; + + for ( var i = 0; i !== stride; ++ i ) { + + result[ i ] = values[ offset + i ]; + + } + + return result; }, - setCrossOrigin: function ( value ) { + // Template methods for derived classes: + + interpolate_: function ( /* i1, t0, t, t1 */ ) { - this.crossOrigin = value; - return this; + throw new Error( 'call to abstract method' ); + // implementations shall return this.resultBuffer }, - setPath: function ( value ) { + intervalChanged_: function ( /* i1, t0, t1 */ ) { - this.path = value; - return this; + // empty } } ); + // DECLARE ALIAS AFTER assign prototype + Object.assign( Interpolant.prototype, { + + //( 0, t, t0 ), returns this.resultBuffer + beforeStart_: Interpolant.prototype.copySampleValue_, + + //( N-1, tN-1, t ), returns this.resultBuffer + afterEnd_: Interpolant.prototype.copySampleValue_, + + } ); + /** - * @author mrdoob / http://mrdoob.com/ + * 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. */ + function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - function CubeTextureLoader( manager ) { + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this._weightPrev = - 0; + this._offsetPrev = - 0; + this._weightNext = - 0; + this._offsetNext = - 0; } - Object.assign( CubeTextureLoader.prototype, { + CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - crossOrigin: 'anonymous', + constructor: CubicInterpolant, - load: function ( urls, onLoad, onProgress, onError ) { + DefaultSettings_: { - var texture = new CubeTexture(); + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding - var loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); + }, - var loaded = 0; + intervalChanged_: function ( i1, t0, t1 ) { - function loadTexture( i ) { + var pp = this.parameterPositions, + iPrev = i1 - 2, + iNext = i1 + 1, - loader.load( urls[ i ], function ( image ) { + tPrev = pp[ iPrev ], + tNext = pp[ iNext ]; - texture.images[ i ] = image; + if ( tPrev === undefined ) { - loaded ++; + switch ( this.getSettings_().endingStart ) { - if ( loaded === 6 ) { + case ZeroSlopeEnding: - texture.needsUpdate = true; + // f'(t0) = 0 + iPrev = i1; + tPrev = 2 * t0 - t1; - if ( onLoad ) onLoad( texture ); + break; - } + case WrapAroundEnding: - }, undefined, onError ); + // use the other end of the curve + iPrev = pp.length - 2; + tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; - } + break; - for ( var i = 0; i < urls.length; ++ i ) { + default: // ZeroCurvatureEnding - loadTexture( i ); + // f''(t0) = 0 a.k.a. Natural Spline + iPrev = i1; + tPrev = t1; + + } } - return texture; + if ( tNext === undefined ) { - }, + switch ( this.getSettings_().endingEnd ) { - setCrossOrigin: function ( value ) { + case ZeroSlopeEnding: - this.crossOrigin = value; - return this; + // f'(tN) = 0 + iNext = i1; + tNext = 2 * t1 - t0; - }, + break; - setPath: function ( value ) { + case WrapAroundEnding: - this.path = value; - return this; + // use the other end of the curve + iNext = 1; + tNext = t1 + pp[ 1 ] - pp[ 0 ]; - } + break; - } ); + default: // ZeroCurvatureEnding - /** - * @author mrdoob / http://mrdoob.com/ - */ + // f''(tN) = 0, a.k.a. Natural Spline + iNext = i1 - 1; + tNext = t0; + } - function TextureLoader( manager ) { + } - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + var halfDt = ( t1 - t0 ) * 0.5, + stride = this.valueSize; - } + this._weightPrev = halfDt / ( t0 - tPrev ); + this._weightNext = halfDt / ( tNext - t1 ); + this._offsetPrev = iPrev * stride; + this._offsetNext = iNext * stride; - Object.assign( TextureLoader.prototype, { + }, - crossOrigin: 'anonymous', + interpolate_: function ( i1, t0, t, t1 ) { - load: function ( url, onLoad, onProgress, onError ) { + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - var texture = new Texture(); + o1 = i1 * stride, o0 = o1 - stride, + oP = this._offsetPrev, oN = this._offsetNext, + wP = this._weightPrev, wN = this._weightNext, - var loader = new ImageLoader( this.manager ); - loader.setCrossOrigin( this.crossOrigin ); - loader.setPath( this.path ); + p = ( t - t0 ) / ( t1 - t0 ), + pp = p * p, + ppp = pp * p; - loader.load( url, function ( image ) { + // evaluate polynomials - texture.image = image; + var sP = - wP * ppp + 2 * wP * pp - wP * p; + var s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; + var s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; + var sN = wN * ppp - wN * pp; - // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. - var isJPEG = url.search( /\.jpe?g$/i ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; + // combine data linearly - texture.format = isJPEG ? RGBFormat : RGBAFormat; - texture.needsUpdate = true; + for ( var i = 0; i !== stride; ++ i ) { - if ( onLoad !== undefined ) { + result[ i ] = + sP * values[ oP + i ] + + s0 * values[ o0 + i ] + + s1 * values[ o1 + i ] + + sN * values[ oN + i ]; - onLoad( texture ); + } - } + return result; - }, onProgress, onError ); + } - return texture; + } ); - }, + function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - setCrossOrigin: function ( value ) { + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - this.crossOrigin = value; - return this; + } - }, + LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - setPath: function ( value ) { + constructor: LinearInterpolant, - this.path = value; - return this; + interpolate_: function ( i1, t0, t, t1 ) { - } + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - } ); + offset1 = i1 * stride, + offset0 = offset1 - stride, - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Extensible curve object - * - * Some common of curve methods: - * .getPoint( t, optionalTarget ), .getTangent( t ) - * .getPointAt( u, optionalTarget ), .getTangentAt( u ) - * .getPoints(), .getSpacedPoints() - * .getLength() - * .updateArcLengths() - * - * This following curves inherit from THREE.Curve: - * - * -- 2D curves -- - * THREE.ArcCurve - * THREE.CubicBezierCurve - * THREE.EllipseCurve - * THREE.LineCurve - * THREE.QuadraticBezierCurve - * THREE.SplineCurve - * - * -- 3D curves -- - * THREE.CatmullRomCurve3 - * THREE.CubicBezierCurve3 - * THREE.LineCurve3 - * THREE.QuadraticBezierCurve3 - * - * A series of curves can be represented as a THREE.CurvePath. - * - **/ + weight1 = ( t - t0 ) / ( t1 - t0 ), + weight0 = 1 - weight1; - /************************************************************** - * Abstract Curve base class - **************************************************************/ + for ( var i = 0; i !== stride; ++ i ) { - function Curve() { + result[ i ] = + values[ offset0 + i ] * weight0 + + values[ offset1 + i ] * weight1; - this.type = 'Curve'; + } - this.arcLengthDivisions = 200; + return result; - } + } - Object.assign( Curve.prototype, { + } ); - // Virtual base class method to overwrite and implement in subclasses - // - t [0 .. 1] + /** + * + * Interpolant that evaluates to the sample value at the position preceeding + * the parameter. + */ - getPoint: function ( /* t, optionalTarget */ ) { + function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - console.warn( 'THREE.Curve: .getPoint() not implemented.' ); - return null; + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - }, + } - // Get point at relative position in curve according to arc length - // - u [0 .. 1] + DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - getPointAt: function ( u, optionalTarget ) { + constructor: DiscreteInterpolant, - var t = this.getUtoTmapping( u ); - return this.getPoint( t, optionalTarget ); + interpolate_: function ( i1 /*, t0, t, t1 */ ) { - }, + return this.copySampleValue_( i1 - 1 ); - // Get sequence of points using getPoint( t ) + } - getPoints: function ( divisions ) { + } ); - if ( divisions === undefined ) divisions = 5; + function KeyframeTrack( name, times, values, interpolation ) { - var points = []; + if ( name === undefined ) { throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); } + if ( times === undefined || times.length === 0 ) { throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); } - for ( var d = 0; d <= divisions; d ++ ) { + this.name = name; - points.push( this.getPoint( d / divisions ) ); + this.times = AnimationUtils.convertArray( times, this.TimeBufferType ); + this.values = AnimationUtils.convertArray( values, this.ValueBufferType ); - } + this.setInterpolation( interpolation || this.DefaultInterpolation ); - return points; + } - }, + // Static methods - // Get sequence of points using getPointAt( u ) + Object.assign( KeyframeTrack, { - getSpacedPoints: function ( divisions ) { + // Serialization (in static context, because of constructor invocation + // and automatic invocation of .toJSON): - if ( divisions === undefined ) divisions = 5; + toJSON: function ( track ) { - var points = []; + var trackType = track.constructor; - for ( var d = 0; d <= divisions; d ++ ) { + var json; - points.push( this.getPointAt( d / divisions ) ); + // derived classes can define a static toJSON method + if ( trackType.toJSON !== undefined ) { - } + json = trackType.toJSON( track ); - return points; + } else { - }, + // by default, we assume the data can be serialized as-is + json = { - // Get total curve arc length + 'name': track.name, + 'times': AnimationUtils.convertArray( track.times, Array ), + 'values': AnimationUtils.convertArray( track.values, Array ) - getLength: function () { + }; - var lengths = this.getLengths(); - return lengths[ lengths.length - 1 ]; + var interpolation = track.getInterpolation(); - }, + if ( interpolation !== track.DefaultInterpolation ) { - // Get list of cumulative segment lengths + json.interpolation = interpolation; - getLengths: function ( divisions ) { + } - if ( divisions === undefined ) divisions = this.arcLengthDivisions; + } - if ( this.cacheArcLengths && - ( this.cacheArcLengths.length === divisions + 1 ) && - ! this.needsUpdate ) { + json.type = track.ValueTypeName; // mandatory - return this.cacheArcLengths; + return json; - } + } - this.needsUpdate = false; + } ); - var cache = []; - var current, last = this.getPoint( 0 ); - var p, sum = 0; + Object.assign( KeyframeTrack.prototype, { - cache.push( 0 ); + constructor: KeyframeTrack, - for ( p = 1; p <= divisions; p ++ ) { + TimeBufferType: Float32Array, - current = this.getPoint( p / divisions ); - sum += current.distanceTo( last ); - cache.push( sum ); - last = current; + ValueBufferType: Float32Array, - } + DefaultInterpolation: InterpolateLinear, - this.cacheArcLengths = cache; + InterpolantFactoryMethodDiscrete: function ( result ) { - return cache; // { sums: cache, sum: sum }; Sum is in the last element. + return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); }, - updateArcLengths: function () { + InterpolantFactoryMethodLinear: function ( result ) { - this.needsUpdate = true; - this.getLengths(); + return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); }, - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant + InterpolantFactoryMethodSmooth: function ( result ) { - getUtoTmapping: function ( u, distance ) { + return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); - var arcLengths = this.getLengths(); + }, - var i = 0, il = arcLengths.length; + setInterpolation: function ( interpolation ) { - var targetArcLength; // The targeted u distance value to get + var factoryMethod; - if ( distance ) { + switch ( interpolation ) { - targetArcLength = distance; + case InterpolateDiscrete: - } else { + factoryMethod = this.InterpolantFactoryMethodDiscrete; - targetArcLength = u * arcLengths[ il - 1 ]; + break; - } + case InterpolateLinear: - // binary search for the index with largest value smaller than target u distance + factoryMethod = this.InterpolantFactoryMethodLinear; - var low = 0, high = il - 1, comparison; + break; - while ( low <= high ) { + case InterpolateSmooth: - 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 + factoryMethod = this.InterpolantFactoryMethodSmooth; - comparison = arcLengths[ i ] - targetArcLength; + break; - if ( comparison < 0 ) { + } - low = i + 1; + if ( factoryMethod === undefined ) { - } else if ( comparison > 0 ) { + var message = "unsupported interpolation for " + + this.ValueTypeName + " keyframe track named " + this.name; - high = i - 1; + if ( this.createInterpolant === undefined ) { - } else { + // fall back to default, unless the default itself is messed up + if ( interpolation !== this.DefaultInterpolation ) { - high = i; - break; + this.setInterpolation( this.DefaultInterpolation ); - // DONE + } else { + + throw new Error( message ); // fatal, in this case + + } } + console.warn( 'THREE.KeyframeTrack:', message ); + return this; + } - i = high; + this.createInterpolant = factoryMethod; - if ( arcLengths[ i ] === targetArcLength ) { + return this; - return i / ( il - 1 ); + }, - } + getInterpolation: function () { - // we could get finer grain at lengths, or use simple interpolation between two points + switch ( this.createInterpolant ) { - var lengthBefore = arcLengths[ i ]; - var lengthAfter = arcLengths[ i + 1 ]; + case this.InterpolantFactoryMethodDiscrete: - var segmentLength = lengthAfter - lengthBefore; + return InterpolateDiscrete; - // determine where we are between the 'before' and 'after' points + case this.InterpolantFactoryMethodLinear: - var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; + return InterpolateLinear; - // add that fractional amount to t + case this.InterpolantFactoryMethodSmooth: - var t = ( i + segmentFraction ) / ( il - 1 ); + return InterpolateSmooth; - 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 + getValueSize: function () { - getTangent: function ( t ) { + return this.values.length / this.times.length; - var delta = 0.0001; - var t1 = t - delta; - var t2 = t + delta; + }, - // Capping in case of danger + // move all keyframes either forwards or backwards in time + shift: function ( timeOffset ) { - if ( t1 < 0 ) t1 = 0; - if ( t2 > 1 ) t2 = 1; + if ( timeOffset !== 0.0 ) { - var pt1 = this.getPoint( t1 ); - var pt2 = this.getPoint( t2 ); + var times = this.times; - var vec = pt2.clone().sub( pt1 ); - return vec.normalize(); + for ( var i = 0, n = times.length; i !== n; ++ i ) { - }, + times[ i ] += timeOffset; - getTangentAt: function ( u ) { + } - var t = this.getUtoTmapping( u ); - return this.getTangent( t ); + } - }, + return this; - computeFrenetFrames: function ( segments, closed ) { + }, - // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf + // scale all keyframe times by a factor (useful for frame <-> seconds conversions) + scale: function ( timeScale ) { - var normal = new Vector3(); + if ( timeScale !== 1.0 ) { - var tangents = []; - var normals = []; - var binormals = []; + var times = this.times; - var vec = new Vector3(); - var mat = new Matrix4(); + for ( var i = 0, n = times.length; i !== n; ++ i ) { - var i, u, theta; + times[ i ] *= timeScale; - // compute the tangent vectors for each segment on the curve + } - for ( i = 0; i <= segments; i ++ ) { + } - u = i / segments; + return this; - tangents[ i ] = this.getTangentAt( u ); - tangents[ i ].normalize(); + }, - } + // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. + // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values + trim: function ( startTime, endTime ) { - // select an initial normal vector perpendicular to the first tangent vector, - // and in the direction of the minimum tangent xyz component + var times = this.times, + nKeys = times.length; - normals[ 0 ] = new Vector3(); - binormals[ 0 ] = new Vector3(); - var min = Number.MAX_VALUE; - var tx = Math.abs( tangents[ 0 ].x ); - var ty = Math.abs( tangents[ 0 ].y ); - var tz = Math.abs( tangents[ 0 ].z ); + var from = 0, + to = nKeys - 1; - if ( tx <= min ) { + while ( from !== nKeys && times[ from ] < startTime ) { - min = tx; - normal.set( 1, 0, 0 ); + ++ from; } - if ( ty <= min ) { + while ( to !== - 1 && times[ to ] > endTime ) { - min = ty; - normal.set( 0, 1, 0 ); + -- to; } - if ( tz <= min ) { + ++ to; // inclusive -> exclusive bound - normal.set( 0, 0, 1 ); + if ( from !== 0 || to !== nKeys ) { - } + // empty tracks are forbidden, so keep at least one keyframe + if ( from >= to ) { - vec.crossVectors( tangents[ 0 ], normal ).normalize(); + to = Math.max( to, 1 ); + from = to - 1; - normals[ 0 ].crossVectors( tangents[ 0 ], vec ); - binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); + } + var stride = this.getValueSize(); + this.times = AnimationUtils.arraySlice( times, from, to ); + this.values = AnimationUtils.arraySlice( this.values, from * stride, to * stride ); - // compute the slowly-varying normal and binormal vectors for each segment on the curve + } - for ( i = 1; i <= segments; i ++ ) { + return this; - normals[ i ] = normals[ i - 1 ].clone(); + }, - binormals[ i ] = binormals[ i - 1 ].clone(); + // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable + validate: function () { - vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); + var valid = true; - if ( vec.length() > Number.EPSILON ) { + var valueSize = this.getValueSize(); + if ( valueSize - Math.floor( valueSize ) !== 0 ) { - vec.normalize(); + console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); + valid = false; + + } - theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors + var times = this.times, + values = this.values, - normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); + nKeys = times.length; - } + if ( nKeys === 0 ) { - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + console.error( 'THREE.KeyframeTrack: Track is empty.', this ); + valid = false; } - // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same + var prevTime = null; - if ( closed === true ) { + for ( var i = 0; i !== nKeys; i ++ ) { - theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); - theta /= segments; + var currTime = times[ i ]; - if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { + if ( typeof currTime === 'number' && isNaN( currTime ) ) { - theta = - theta; + console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); + valid = false; + break; } - for ( i = 1; i <= segments; i ++ ) { + if ( prevTime !== null && prevTime > currTime ) { - // twist a little... - normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); - binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); + console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); + valid = false; + break; } - } - - return { - tangents: tangents, - normals: normals, - binormals: binormals - }; + prevTime = currTime; - }, + } - clone: function () { + if ( values !== undefined ) { - return new this.constructor().copy( this ); + if ( AnimationUtils.isTypedArray( values ) ) { - }, + for ( var i$1 = 0, n = values.length; i$1 !== n; ++ i$1 ) { - copy: function ( source ) { + var value = values[ i$1 ]; - this.arcLengthDivisions = source.arcLengthDivisions; + if ( isNaN( value ) ) { - return this; + console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i$1, value ); + valid = false; + break; - }, + } - toJSON: function () { + } - var data = { - metadata: { - version: 4.5, - type: 'Curve', - generator: 'Curve.toJSON' } - }; - data.arcLengthDivisions = this.arcLengthDivisions; - data.type = this.type; + } - return data; + return valid; }, - fromJSON: function ( json ) { + // removes equivalent sequential keys as common in morph target sequences + // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) + optimize: function () { - this.arcLengthDivisions = json.arcLengthDivisions; + // times or values may be shared with other tracks, so overwriting is unsafe + var times = AnimationUtils.arraySlice( this.times ), + values = AnimationUtils.arraySlice( this.values ), + stride = this.getValueSize(), - return this; + smoothInterpolation = this.getInterpolation() === InterpolateSmooth, - } + lastIndex = times.length - 1; - } ); + var writeIndex = 1; - function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + for ( var i = 1; i < lastIndex; ++ i ) { - Curve.call( this ); + var keep = false; - this.type = 'EllipseCurve'; + var time = times[ i ]; + var timeNext = times[ i + 1 ]; - this.aX = aX || 0; - this.aY = aY || 0; + // remove adjacent keyframes scheduled at the same time - this.xRadius = xRadius || 1; - this.yRadius = yRadius || 1; + if ( time !== timeNext && ( i !== 1 || time !== time[ 0 ] ) ) { - this.aStartAngle = aStartAngle || 0; - this.aEndAngle = aEndAngle || 2 * Math.PI; + if ( ! smoothInterpolation ) { - this.aClockwise = aClockwise || false; + // remove unnecessary keyframes same as their neighbors - this.aRotation = aRotation || 0; + var offset = i * stride, + offsetP = offset - stride, + offsetN = offset + stride; - } + for ( var j = 0; j !== stride; ++ j ) { - EllipseCurve.prototype = Object.create( Curve.prototype ); - EllipseCurve.prototype.constructor = EllipseCurve; + var value = values[ offset + j ]; - EllipseCurve.prototype.isEllipseCurve = true; + if ( value !== values[ offsetP + j ] || + value !== values[ offsetN + j ] ) { - EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) { + keep = true; + break; - var point = optionalTarget || new Vector2(); + } - var twoPi = Math.PI * 2; - var deltaAngle = this.aEndAngle - this.aStartAngle; - var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; + } - // ensures that deltaAngle is 0 .. 2 PI - while ( deltaAngle < 0 ) deltaAngle += twoPi; - while ( deltaAngle > twoPi ) deltaAngle -= twoPi; + } else { - if ( deltaAngle < Number.EPSILON ) { + keep = true; - if ( samePoints ) { + } - deltaAngle = 0; + } - } else { + // in-place compaction - deltaAngle = twoPi; + if ( keep ) { - } + if ( i !== writeIndex ) { - } + times[ writeIndex ] = times[ i ]; - if ( this.aClockwise === true && ! samePoints ) { + var readOffset = i * stride, + writeOffset = writeIndex * stride; - if ( deltaAngle === twoPi ) { + for ( var j$1 = 0; j$1 !== stride; ++ j$1 ) { - deltaAngle = - twoPi; + values[ writeOffset + j$1 ] = values[ readOffset + j$1 ]; - } else { + } - deltaAngle = deltaAngle - twoPi; + } + + ++ writeIndex; + + } } - } + // flush last keyframe (compaction looks ahead) - var angle = this.aStartAngle + t * deltaAngle; - var x = this.aX + this.xRadius * Math.cos( angle ); - var y = this.aY + this.yRadius * Math.sin( angle ); + if ( lastIndex > 0 ) { - if ( this.aRotation !== 0 ) { + times[ writeIndex ] = times[ lastIndex ]; - var cos = Math.cos( this.aRotation ); - var sin = Math.sin( this.aRotation ); + for ( var readOffset$1 = lastIndex * stride, writeOffset$1 = writeIndex * stride, j$2 = 0; j$2 !== stride; ++ j$2 ) { - var tx = x - this.aX; - var ty = y - this.aY; + values[ writeOffset$1 + j$2 ] = values[ readOffset$1 + j$2 ]; - // Rotate the point about the center of the ellipse. - x = tx * cos - ty * sin + this.aX; - y = tx * sin + ty * cos + this.aY; + } - } + ++ writeIndex; - return point.set( x, y ); + } - }; + if ( writeIndex !== times.length ) { - EllipseCurve.prototype.copy = function ( source ) { + this.times = AnimationUtils.arraySlice( times, 0, writeIndex ); + this.values = AnimationUtils.arraySlice( values, 0, writeIndex * stride ); - Curve.prototype.copy.call( this, source ); + } else { - this.aX = source.aX; - this.aY = source.aY; + this.times = times; + this.values = values; - this.xRadius = source.xRadius; - this.yRadius = source.yRadius; + } - this.aStartAngle = source.aStartAngle; - this.aEndAngle = source.aEndAngle; + return this; - this.aClockwise = source.aClockwise; + }, - this.aRotation = source.aRotation; + clone: function () { - return this; + var times = AnimationUtils.arraySlice( this.times, 0 ); + var values = AnimationUtils.arraySlice( this.values, 0 ); - }; + var TypedKeyframeTrack = this.constructor; + var track = new TypedKeyframeTrack( this.name, times, values ); + // Interpolant argument to constructor is not saved, so copy the factory method directly. + track.createInterpolant = this.createInterpolant; - EllipseCurve.prototype.toJSON = function () { + return track; - var data = Curve.prototype.toJSON.call( this ); + } - data.aX = this.aX; - data.aY = this.aY; + } ); - data.xRadius = this.xRadius; - data.yRadius = this.yRadius; + /** + * A Track of Boolean keyframe values. + */ - data.aStartAngle = this.aStartAngle; - data.aEndAngle = this.aEndAngle; + function BooleanKeyframeTrack( name, times, values ) { - data.aClockwise = this.aClockwise; + KeyframeTrack.call( this, name, times, values ); - data.aRotation = this.aRotation; + } - return data; + BooleanKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - }; + constructor: BooleanKeyframeTrack, - EllipseCurve.prototype.fromJSON = function ( json ) { + ValueTypeName: 'bool', + ValueBufferType: Array, - Curve.prototype.fromJSON.call( this, json ); + DefaultInterpolation: InterpolateDiscrete, - this.aX = json.aX; - this.aY = json.aY; + InterpolantFactoryMethodLinear: undefined, + InterpolantFactoryMethodSmooth: undefined - this.xRadius = json.xRadius; - this.yRadius = json.yRadius; + // Note: Actually this track could have a optimized / compressed + // representation of a single value and a custom interpolant that + // computes "firstValue ^ isOdd( index )". - this.aStartAngle = json.aStartAngle; - this.aEndAngle = json.aEndAngle; + } ); - this.aClockwise = json.aClockwise; + /** + * A Track of keyframe values that represent color. + */ - this.aRotation = json.aRotation; + function ColorKeyframeTrack( name, times, values, interpolation ) { - return this; + KeyframeTrack.call( this, name, times, values, interpolation ); - }; + } - function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + ColorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + constructor: ColorKeyframeTrack, - this.type = 'ArcCurve'; + ValueTypeName: 'color' - } + // ValueBufferType is inherited - ArcCurve.prototype = Object.create( EllipseCurve.prototype ); - ArcCurve.prototype.constructor = ArcCurve; + // DefaultInterpolation is inherited - ArcCurve.prototype.isArcCurve = true; + // Note: Very basic implementation and nothing special yet. + // However, this is the place for color space parameterization. + + } ); /** - * @author zz85 https://github.com/zz85 - * - * Centripetal CatmullRom Curve - which is useful for avoiding - * cusps and self-intersections in non-uniform catmull rom curves. - * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf - * - * curve.type accepts centripetal(default), chordal and catmullrom - * curve.tension is used for catmullrom which defaults to 0.5 + * A Track of numeric keyframe values. */ + function NumberKeyframeTrack( name, times, values, interpolation ) { - /* - 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 + KeyframeTrack.call( this, name, times, values, interpolation ); - 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() { + NumberKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - var c0 = 0, c1 = 0, c2 = 0, c3 = 0; + constructor: NumberKeyframeTrack, - /* - * 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 ) { + ValueTypeName: 'number' - c0 = x0; - c1 = t0; - c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; - c3 = 2 * x0 - 2 * x1 + t0 + t1; + // ValueBufferType is inherited - } + // DefaultInterpolation is inherited - return { + } ); - initCatmullRom: function ( x0, x1, x2, x3, tension ) { + /** + * Spherical linear unit quaternion interpolant. + */ - init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); + function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) { - }, + Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer ); - initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { + } - // compute tangents when parameterized in [t1,t2] - var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; - var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; + QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), { - // rescale tangents for parametrization in [0,1] - t1 *= dt1; - t2 *= dt1; + constructor: QuaternionLinearInterpolant, - init( x1, x2, t1, t2 ); + interpolate_: function ( i1, t0, t, t1 ) { - }, + var result = this.resultBuffer, + values = this.sampleValues, + stride = this.valueSize, - calc: function ( t ) { + alpha = ( t - t0 ) / ( t1 - t0 ); - var t2 = t * t; - var t3 = t2 * t; - return c0 + c1 * t + c2 * t2 + c3 * t3; + var offset = i1 * stride; - } + for ( var end = offset + stride; offset !== end; offset += 4 ) { - }; + Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); - } + } - // + return result; - var tmp = new Vector3(); - var px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly(); + } - function CatmullRomCurve3( points, closed, curveType, tension ) { + } ); - Curve.call( this ); + /** + * A Track of quaternion keyframe values. + */ - this.type = 'CatmullRomCurve3'; + function QuaternionKeyframeTrack( name, times, values, interpolation ) { - this.points = points || []; - this.closed = closed || false; - this.curveType = curveType || 'centripetal'; - this.tension = tension || 0.5; + KeyframeTrack.call( this, name, times, values, interpolation ); } - CatmullRomCurve3.prototype = Object.create( Curve.prototype ); - CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; + QuaternionKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; + constructor: QuaternionKeyframeTrack, - CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) { + ValueTypeName: 'quaternion', - var point = optionalTarget || new Vector3(); + // ValueBufferType is inherited - var points = this.points; - var l = points.length; + DefaultInterpolation: InterpolateLinear, - var p = ( l - ( this.closed ? 0 : 1 ) ) * t; - var intPoint = Math.floor( p ); - var weight = p - intPoint; + InterpolantFactoryMethodLinear: function ( result ) { - if ( this.closed ) { + return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); - intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; + }, - } else if ( weight === 0 && intPoint === l - 1 ) { + InterpolantFactoryMethodSmooth: undefined // not yet implemented - intPoint = l - 2; - weight = 1; + } ); - } + /** + * A Track that interpolates Strings + */ - var p0, p1, p2, p3; // 4 points + function StringKeyframeTrack( name, times, values, interpolation ) { - if ( this.closed || intPoint > 0 ) { + KeyframeTrack.call( this, name, times, values, interpolation ); - p0 = points[ ( intPoint - 1 ) % l ]; + } - } else { + StringKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - // extrapolate first point - tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); - p0 = tmp; + constructor: StringKeyframeTrack, - } + ValueTypeName: 'string', + ValueBufferType: Array, - p1 = points[ intPoint % l ]; - p2 = points[ ( intPoint + 1 ) % l ]; + DefaultInterpolation: InterpolateDiscrete, - if ( this.closed || intPoint + 2 < l ) { + InterpolantFactoryMethodLinear: undefined, - p3 = points[ ( intPoint + 2 ) % l ]; + InterpolantFactoryMethodSmooth: undefined - } else { + } ); - // extrapolate last point - tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); - p3 = tmp; + /** + * A Track of vectored keyframe values. + */ - } + function VectorKeyframeTrack( name, times, values, interpolation ) { - if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { + KeyframeTrack.call( this, name, times, values, interpolation ); - // init Centripetal / Chordal Catmull-Rom - var pow = this.curveType === 'chordal' ? 0.5 : 0.25; - var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); - var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); - var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); + } - // safety check for repeated points - if ( dt1 < 1e-4 ) dt1 = 1.0; - if ( dt0 < 1e-4 ) dt0 = dt1; - if ( dt2 < 1e-4 ) dt2 = dt1; + VectorKeyframeTrack.prototype = Object.assign( Object.create( KeyframeTrack.prototype ), { - 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 ); + constructor: VectorKeyframeTrack, - } else if ( this.curveType === 'catmullrom' ) { + ValueTypeName: 'vector' - 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 ); + // ValueBufferType is inherited - } + // DefaultInterpolation is inherited - point.set( - px.calc( weight ), - py.calc( weight ), - pz.calc( weight ) - ); + } ); - return point; + function AnimationClip( name, duration, tracks, blendMode ) { - }; + this.name = name; + this.tracks = tracks; + this.duration = ( duration !== undefined ) ? duration : - 1; + this.blendMode = ( blendMode !== undefined ) ? blendMode : NormalAnimationBlendMode; - CatmullRomCurve3.prototype.copy = function ( source ) { + this.uuid = MathUtils.generateUUID(); - Curve.prototype.copy.call( this, source ); + // this means it should figure out its duration by scanning the tracks + if ( this.duration < 0 ) { - this.points = []; + this.resetDuration(); - for ( var i = 0, l = source.points.length; i < l; i ++ ) { + } - var point = source.points[ i ]; + } - this.points.push( point.clone() ); + function getTrackTypeForValueTypeName( typeName ) { - } + switch ( typeName.toLowerCase() ) { - this.closed = source.closed; - this.curveType = source.curveType; - this.tension = source.tension; + case 'scalar': + case 'double': + case 'float': + case 'number': + case 'integer': - return this; + return NumberKeyframeTrack; - }; + case 'vector': + case 'vector2': + case 'vector3': + case 'vector4': - CatmullRomCurve3.prototype.toJSON = function () { + return VectorKeyframeTrack; - var data = Curve.prototype.toJSON.call( this ); + case 'color': - data.points = []; + return ColorKeyframeTrack; - for ( var i = 0, l = this.points.length; i < l; i ++ ) { + case 'quaternion': - var point = this.points[ i ]; - data.points.push( point.toArray() ); + return QuaternionKeyframeTrack; - } + case 'bool': + case 'boolean': - data.closed = this.closed; - data.curveType = this.curveType; - data.tension = this.tension; + return BooleanKeyframeTrack; - return data; + case 'string': - }; + return StringKeyframeTrack; - CatmullRomCurve3.prototype.fromJSON = function ( json ) { + } - Curve.prototype.fromJSON.call( this, json ); + throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); - this.points = []; + } - for ( var i = 0, l = json.points.length; i < l; i ++ ) { + function parseKeyframeTrack( json ) { - var point = json.points[ i ]; - this.points.push( new Vector3().fromArray( point ) ); + if ( json.type === undefined ) { + + throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); } - this.closed = json.closed; - this.curveType = json.curveType; - this.tension = json.tension; + var trackType = getTrackTypeForValueTypeName( json.type ); - return this; + if ( json.times === undefined ) { - }; + var times = [], values = []; - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - * Bezier Curves formulas obtained from - * http://en.wikipedia.org/wiki/Bézier_curve - */ + AnimationUtils.flattenJSON( json.keys, times, values, 'value' ); - function CatmullRom( t, p0, p1, p2, p3 ) { + json.times = times; + json.values = values; - var v0 = ( p2 - p0 ) * 0.5; - var v1 = ( p3 - p1 ) * 0.5; - var t2 = t * t; - var t3 = t * t2; - return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; + } - } + // derived classes can define a static parse method + if ( trackType.parse !== undefined ) { - // + return trackType.parse( json ); - function QuadraticBezierP0( t, p ) { + } else { - var k = 1 - t; - return k * k * p; + // by default, we assume a constructor compatible with the base + return new trackType( json.name, json.times, json.values, json.interpolation ); + + } } - function QuadraticBezierP1( t, p ) { + Object.assign( AnimationClip, { - return 2 * ( 1 - t ) * t * p; + parse: function ( json ) { - } + var tracks = [], + jsonTracks = json.tracks, + frameTime = 1.0 / ( json.fps || 1.0 ); - function QuadraticBezierP2( t, p ) { + for ( var i = 0, n = jsonTracks.length; i !== n; ++ i ) { - return t * t * p; + tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); - } + } - function QuadraticBezier( t, p0, p1, p2 ) { + return new AnimationClip( json.name, json.duration, tracks, json.blendMode ); - return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + - QuadraticBezierP2( t, p2 ); + }, - } + toJSON: function ( clip ) { - // + var tracks = [], + clipTracks = clip.tracks; - function CubicBezierP0( t, p ) { + var json = { - var k = 1 - t; - return k * k * k * p; + 'name': clip.name, + 'duration': clip.duration, + 'tracks': tracks, + 'uuid': clip.uuid, + 'blendMode': clip.blendMode - } + }; - function CubicBezierP1( t, p ) { + for ( var i = 0, n = clipTracks.length; i !== n; ++ i ) { - var k = 1 - t; - return 3 * k * k * t * p; + tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); - } + } - function CubicBezierP2( t, p ) { + return json; - return 3 * ( 1 - t ) * t * t * p; + }, - } + CreateFromMorphTargetSequence: function ( name, morphTargetSequence, fps, noLoop ) { - function CubicBezierP3( t, p ) { + var numMorphTargets = morphTargetSequence.length; + var tracks = []; - return t * t * t * p; + for ( var i = 0; i < numMorphTargets; i ++ ) { - } + var times = []; + var values = []; - function CubicBezier( t, p0, p1, p2, p3 ) { + times.push( + ( i + numMorphTargets - 1 ) % numMorphTargets, + i, + ( i + 1 ) % numMorphTargets ); - return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + - CubicBezierP3( t, p3 ); + values.push( 0, 1, 0 ); - } + var order = AnimationUtils.getKeyframeOrder( times ); + times = AnimationUtils.sortedArray( times, 1, order ); + values = AnimationUtils.sortedArray( values, 1, order ); - function CubicBezierCurve( v0, v1, v2, v3 ) { + // 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 ) { - Curve.call( this ); + times.push( numMorphTargets ); + values.push( values[ 0 ] ); - this.type = 'CubicBezierCurve'; + } - this.v0 = v0 || new Vector2(); - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); - this.v3 = v3 || new Vector2(); + tracks.push( + new NumberKeyframeTrack( + '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', + times, values + ).scale( 1.0 / fps ) ); - } + } - CubicBezierCurve.prototype = Object.create( Curve.prototype ); - CubicBezierCurve.prototype.constructor = CubicBezierCurve; + return new AnimationClip( name, - 1, tracks ); - CubicBezierCurve.prototype.isCubicBezierCurve = true; + }, - CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { + findByName: function ( objectOrClipArray, name ) { - var point = optionalTarget || new Vector2(); + var clipArray = objectOrClipArray; - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + if ( ! Array.isArray( objectOrClipArray ) ) { - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) - ); + var o = objectOrClipArray; + clipArray = o.geometry && o.geometry.animations || o.animations; - return point; + } - }; + for ( var i = 0; i < clipArray.length; i ++ ) { - CubicBezierCurve.prototype.copy = function ( source ) { + if ( clipArray[ i ].name === name ) { - Curve.prototype.copy.call( this, source ); + return clipArray[ i ]; - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); + } - return this; + } - }; + return null; - CubicBezierCurve.prototype.toJSON = function () { + }, - var data = Curve.prototype.toJSON.call( this ); + CreateClipsFromMorphTargetSequences: function ( morphTargets, fps, noLoop ) { - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); + var animationToMorphTargets = {}; - return data; + // tested with https://regex101.com/ on trick sequences + // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 + var pattern = /^([\w-]*?)([\d]+)$/; - }; + // sort morph target names into animation groups based + // patterns like Walk_001, Walk_002, Run_001, Run_002 + for ( var i = 0, il = morphTargets.length; i < il; i ++ ) { - CubicBezierCurve.prototype.fromJSON = function ( json ) { + var morphTarget = morphTargets[ i ]; + var parts = morphTarget.name.match( pattern ); - Curve.prototype.fromJSON.call( this, json ); + if ( parts && parts.length > 1 ) { - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); + var name = parts[ 1 ]; - return this; + var animationMorphTargets = animationToMorphTargets[ name ]; - }; + if ( ! animationMorphTargets ) { - function CubicBezierCurve3( v0, v1, v2, v3 ) { + animationToMorphTargets[ name ] = animationMorphTargets = []; - Curve.call( this ); + } - this.type = 'CubicBezierCurve3'; + animationMorphTargets.push( morphTarget ); - this.v0 = v0 || new Vector3(); - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); - this.v3 = v3 || new Vector3(); + } - } + } - CubicBezierCurve3.prototype = Object.create( Curve.prototype ); - CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; + var clips = []; - CubicBezierCurve3.prototype.isCubicBezierCurve3 = true; + for ( var name$1 in animationToMorphTargets ) { - CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { + clips.push( AnimationClip.CreateFromMorphTargetSequence( name$1, animationToMorphTargets[ name$1 ], fps, noLoop ) ); - var point = optionalTarget || new Vector3(); + } - var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; + return clips; - point.set( - CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), - CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), - CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) - ); + }, - return point; + // parse the animation.hierarchy format + parseAnimation: function ( animation, bones ) { - }; + if ( ! animation ) { - CubicBezierCurve3.prototype.copy = function ( source ) { + console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); + return null; - Curve.prototype.copy.call( this, source ); + } - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); - this.v3.copy( source.v3 ); + var addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { - return this; + // only return track if there are actually keys. + if ( animationKeys.length !== 0 ) { - }; + var times = []; + var values = []; - CubicBezierCurve3.prototype.toJSON = function () { + AnimationUtils.flattenJSON( animationKeys, times, values, propertyName ); - var data = Curve.prototype.toJSON.call( this ); + // empty keys are filtered out, so check again + if ( times.length !== 0 ) { - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); - data.v3 = this.v3.toArray(); + destTracks.push( new trackType( trackName, times, values ) ); - return data; + } - }; + } - CubicBezierCurve3.prototype.fromJSON = function ( json ) { + }; - Curve.prototype.fromJSON.call( this, json ); + var tracks = []; - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); - this.v3.fromArray( json.v3 ); + var clipName = animation.name || 'default'; + var fps = animation.fps || 30; + var blendMode = animation.blendMode; - return this; + // automatic length determination in AnimationClip. + var duration = animation.length || - 1; - }; + var hierarchyTracks = animation.hierarchy || []; - function LineCurve( v1, v2 ) { + for ( var h = 0; h < hierarchyTracks.length; h ++ ) { - Curve.call( this ); + var animationKeys = hierarchyTracks[ h ].keys; - this.type = 'LineCurve'; + // skip empty tracks + if ( ! animationKeys || animationKeys.length === 0 ) { continue; } - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); + // process morph targets + if ( animationKeys[ 0 ].morphTargets ) { - } + // figure out all morph targets used in this track + var morphTargetNames = {}; - LineCurve.prototype = Object.create( Curve.prototype ); - LineCurve.prototype.constructor = LineCurve; + var k = (void 0); - LineCurve.prototype.isLineCurve = true; + for ( k = 0; k < animationKeys.length; k ++ ) { - LineCurve.prototype.getPoint = function ( t, optionalTarget ) { + if ( animationKeys[ k ].morphTargets ) { - var point = optionalTarget || new Vector2(); + for ( var m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { - if ( t === 1 ) { + morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; - point.copy( this.v2 ); + } - } else { + } - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); + } - } + // create a track for each morph target with all zero + // morphTargetInfluences except for the keys in which + // the morphTarget is named. + for ( var morphTargetName in morphTargetNames ) { - return point; + var times = []; + var values = []; - }; + for ( var m$1 = 0; m$1 !== animationKeys[ k ].morphTargets.length; ++ m$1 ) { - // Line curve is linear, so we can overwrite default getPointAt + var animationKey = animationKeys[ k ]; - LineCurve.prototype.getPointAt = function ( u, optionalTarget ) { + times.push( animationKey.time ); + values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); - return this.getPoint( u, optionalTarget ); + } - }; + tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); - LineCurve.prototype.getTangent = function ( /* t */ ) { + } - var tangent = this.v2.clone().sub( this.v1 ); + duration = morphTargetNames.length * ( fps || 1.0 ); - return tangent.normalize(); + } else { - }; + // ...assume skeletal animation - LineCurve.prototype.copy = function ( source ) { + var boneName = '.bones[' + bones[ h ].name + ']'; - Curve.prototype.copy.call( this, source ); + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.position', + animationKeys, 'pos', tracks ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + addNonemptyTrack( + QuaternionKeyframeTrack, boneName + '.quaternion', + animationKeys, 'rot', tracks ); - return this; + addNonemptyTrack( + VectorKeyframeTrack, boneName + '.scale', + animationKeys, 'scl', tracks ); - }; + } - LineCurve.prototype.toJSON = function () { + } - var data = Curve.prototype.toJSON.call( this ); + if ( tracks.length === 0 ) { - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + return null; - return data; + } - }; + var clip = new AnimationClip( clipName, duration, tracks, blendMode ); - LineCurve.prototype.fromJSON = function ( json ) { + return clip; - Curve.prototype.fromJSON.call( this, json ); + } - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + } ); - return this; + Object.assign( AnimationClip.prototype, { - }; + resetDuration: function () { - function LineCurve3( v1, v2 ) { + var tracks = this.tracks; + var duration = 0; - Curve.call( this ); + for ( var i = 0, n = tracks.length; i !== n; ++ i ) { - this.type = 'LineCurve3'; + var track = this.tracks[ i ]; - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); + duration = Math.max( duration, track.times[ track.times.length - 1 ] ); - } + } - LineCurve3.prototype = Object.create( Curve.prototype ); - LineCurve3.prototype.constructor = LineCurve3; + this.duration = duration; - LineCurve3.prototype.isLineCurve3 = true; + return this; - LineCurve3.prototype.getPoint = function ( t, optionalTarget ) { + }, - var point = optionalTarget || new Vector3(); + trim: function () { - if ( t === 1 ) { + for ( var i = 0; i < this.tracks.length; i ++ ) { - point.copy( this.v2 ); + this.tracks[ i ].trim( 0, this.duration ); - } else { + } - point.copy( this.v2 ).sub( this.v1 ); - point.multiplyScalar( t ).add( this.v1 ); + return this; - } + }, - return point; + validate: function () { - }; + var valid = true; - // Line curve is linear, so we can overwrite default getPointAt + for ( var i = 0; i < this.tracks.length; i ++ ) { - LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) { + valid = valid && this.tracks[ i ].validate(); - return this.getPoint( u, optionalTarget ); + } - }; + return valid; - LineCurve3.prototype.copy = function ( source ) { + }, - Curve.prototype.copy.call( this, source ); + optimize: function () { - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + for ( var i = 0; i < this.tracks.length; i ++ ) { - return this; + this.tracks[ i ].optimize(); - }; + } - LineCurve3.prototype.toJSON = function () { + return this; - var data = Curve.prototype.toJSON.call( this ); + }, - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + clone: function () { - return data; + var tracks = []; - }; + for ( var i = 0; i < this.tracks.length; i ++ ) { - LineCurve3.prototype.fromJSON = function ( json ) { + tracks.push( this.tracks[ i ].clone() ); - Curve.prototype.fromJSON.call( this, json ); + } - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + return new AnimationClip( this.name, this.duration, tracks, this.blendMode ); - return this; + } - }; + } ); - function QuadraticBezierCurve( v0, v1, v2 ) { + var Cache = { - Curve.call( this ); + enabled: false, - this.type = 'QuadraticBezierCurve'; + files: {}, - this.v0 = v0 || new Vector2(); - this.v1 = v1 || new Vector2(); - this.v2 = v2 || new Vector2(); + add: function ( key, file ) { - } + if ( this.enabled === false ) { return; } - QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); - QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; + // console.log( 'THREE.Cache', 'Adding key:', key ); - QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; + this.files[ key ] = file; - QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { + }, - var point = optionalTarget || new Vector2(); + get: function ( key ) { - var v0 = this.v0, v1 = this.v1, v2 = this.v2; + if ( this.enabled === false ) { return; } - point.set( - QuadraticBezier( t, v0.x, v1.x, v2.x ), - QuadraticBezier( t, v0.y, v1.y, v2.y ) - ); + // console.log( 'THREE.Cache', 'Checking key:', key ); - return point; + return this.files[ key ]; - }; + }, - QuadraticBezierCurve.prototype.copy = function ( source ) { + remove: function ( key ) { - Curve.prototype.copy.call( this, source ); + delete this.files[ key ]; - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + }, - return this; + clear: function () { - }; + this.files = {}; - QuadraticBezierCurve.prototype.toJSON = function () { + } - var data = Curve.prototype.toJSON.call( this ); + }; - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + function LoadingManager( onLoad, onProgress, onError ) { - return data; + var scope = this; - }; + var isLoading = false; + var itemsLoaded = 0; + var itemsTotal = 0; + var urlModifier = undefined; + var handlers = []; - QuadraticBezierCurve.prototype.fromJSON = function ( json ) { + // Refer to #5689 for the reason why we don't set .onStart + // in the constructor - Curve.prototype.fromJSON.call( this, json ); + this.onStart = undefined; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + this.itemStart = function ( url ) { - return this; + itemsTotal ++; - }; + if ( isLoading === false ) { - function QuadraticBezierCurve3( v0, v1, v2 ) { + if ( scope.onStart !== undefined ) { - Curve.call( this ); + scope.onStart( url, itemsLoaded, itemsTotal ); - this.type = 'QuadraticBezierCurve3'; + } - this.v0 = v0 || new Vector3(); - this.v1 = v1 || new Vector3(); - this.v2 = v2 || new Vector3(); + } - } + isLoading = true; - QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); - QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; + }; - QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; + this.itemEnd = function ( url ) { - QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { + itemsLoaded ++; - var point = optionalTarget || new Vector3(); + if ( scope.onProgress !== undefined ) { - var v0 = this.v0, v1 = this.v1, v2 = this.v2; + scope.onProgress( url, itemsLoaded, itemsTotal ); - 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; + if ( itemsLoaded === itemsTotal ) { - }; + isLoading = false; - QuadraticBezierCurve3.prototype.copy = function ( source ) { + if ( scope.onLoad !== undefined ) { - Curve.prototype.copy.call( this, source ); + scope.onLoad(); - this.v0.copy( source.v0 ); - this.v1.copy( source.v1 ); - this.v2.copy( source.v2 ); + } - return this; + } - }; + }; - QuadraticBezierCurve3.prototype.toJSON = function () { + this.itemError = function ( url ) { - var data = Curve.prototype.toJSON.call( this ); + if ( scope.onError !== undefined ) { - data.v0 = this.v0.toArray(); - data.v1 = this.v1.toArray(); - data.v2 = this.v2.toArray(); + scope.onError( url ); - return data; + } - }; + }; - QuadraticBezierCurve3.prototype.fromJSON = function ( json ) { + this.resolveURL = function ( url ) { - Curve.prototype.fromJSON.call( this, json ); + if ( urlModifier ) { - this.v0.fromArray( json.v0 ); - this.v1.fromArray( json.v1 ); - this.v2.fromArray( json.v2 ); + return urlModifier( url ); - return this; + } - }; + return url; - function SplineCurve( points /* array of Vector2 */ ) { + }; - Curve.call( this ); + this.setURLModifier = function ( transform ) { - this.type = 'SplineCurve'; + urlModifier = transform; - this.points = points || []; + return this; - } + }; - SplineCurve.prototype = Object.create( Curve.prototype ); - SplineCurve.prototype.constructor = SplineCurve; + this.addHandler = function ( regex, loader ) { - SplineCurve.prototype.isSplineCurve = true; + handlers.push( regex, loader ); - SplineCurve.prototype.getPoint = function ( t, optionalTarget ) { + return this; - var point = optionalTarget || new Vector2(); + }; - var points = this.points; - var p = ( points.length - 1 ) * t; + this.removeHandler = function ( regex ) { - var intPoint = Math.floor( p ); - var weight = p - intPoint; + var index = handlers.indexOf( regex ); - var p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; - var p1 = points[ intPoint ]; - var p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; - var p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; + if ( index !== - 1 ) { - point.set( - CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), - CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) - ); + handlers.splice( index, 2 ); - return point; + } - }; + return this; - SplineCurve.prototype.copy = function ( source ) { + }; - Curve.prototype.copy.call( this, source ); + this.getHandler = function ( file ) { - this.points = []; + for ( var i = 0, l = handlers.length; i < l; i += 2 ) { - for ( var i = 0, l = source.points.length; i < l; i ++ ) { + var regex = handlers[ i ]; + var loader = handlers[ i + 1 ]; - var point = source.points[ i ]; + if ( regex.global ) { regex.lastIndex = 0; } // see #17920 - this.points.push( point.clone() ); + if ( regex.test( file ) ) { - } + return loader; - return this; + } - }; + } - SplineCurve.prototype.toJSON = function () { + return null; - var data = Curve.prototype.toJSON.call( this ); + }; - data.points = []; + } - for ( var i = 0, l = this.points.length; i < l; i ++ ) { + var DefaultLoadingManager = new LoadingManager(); - var point = this.points[ i ]; - data.points.push( point.toArray() ); + function Loader( manager ) { - } + this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - return data; + this.crossOrigin = 'anonymous'; + this.path = ''; + this.resourcePath = ''; + this.requestHeader = {}; - }; + } - SplineCurve.prototype.fromJSON = function ( json ) { + Object.assign( Loader.prototype, { - Curve.prototype.fromJSON.call( this, json ); + load: function ( /* url, onLoad, onProgress, onError */ ) {}, - this.points = []; + loadAsync: function ( url, onProgress ) { - for ( var i = 0, l = json.points.length; i < l; i ++ ) { + var scope = this; - var point = json.points[ i ]; - this.points.push( new Vector2().fromArray( point ) ); + return new Promise( function ( resolve, reject ) { - } + scope.load( url, resolve, onProgress, reject ); - return this; + } ); - }; + }, + parse: function ( /* data */ ) {}, + setCrossOrigin: function ( crossOrigin ) { - var Curves = /*#__PURE__*/Object.freeze({ - ArcCurve: ArcCurve, - CatmullRomCurve3: CatmullRomCurve3, - CubicBezierCurve: CubicBezierCurve, - CubicBezierCurve3: CubicBezierCurve3, - EllipseCurve: EllipseCurve, - LineCurve: LineCurve, - LineCurve3: LineCurve3, - QuadraticBezierCurve: QuadraticBezierCurve, - QuadraticBezierCurve3: QuadraticBezierCurve3, - SplineCurve: SplineCurve - }); + this.crossOrigin = crossOrigin; + return this; - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * - **/ + }, - /************************************************************** - * Curved Path - a curve path is simply a array of connected - * curves, but retains the api of a curve - **************************************************************/ + setPath: function ( path ) { - function CurvePath() { + this.path = path; + return this; - Curve.call( this ); + }, - this.type = 'CurvePath'; + setResourcePath: function ( resourcePath ) { - this.curves = []; - this.autoClose = false; // Automatically closes the path + this.resourcePath = resourcePath; + return this; - } + }, - CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { + setRequestHeader: function ( requestHeader ) { - constructor: CurvePath, + this.requestHeader = requestHeader; + return this; - add: function ( curve ) { + } - this.curves.push( curve ); + } ); - }, + var loading = {}; - closePath: function () { + function FileLoader( manager ) { - // Add a line curve if start and end of lines are not connected - var startPoint = this.curves[ 0 ].getPoint( 0 ); - var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); + Loader.call( this, manager ); - if ( ! startPoint.equals( endPoint ) ) { + } - this.curves.push( new LineCurve( endPoint, startPoint ) ); + FileLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - } + constructor: FileLoader, - }, + load: function ( url, onLoad, onProgress, onError ) { - // To get accurate point with reference to - // entire path distance at time t, - // following has to be done: + if ( url === undefined ) { url = ''; } - // 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') + if ( this.path !== undefined ) { url = this.path + url; } - getPoint: function ( t ) { + url = this.manager.resolveURL( url ); - var d = t * this.getLength(); - var curveLengths = this.getCurveLengths(); - var i = 0; + var scope = this; - // To think about boundaries points. + var cached = Cache.get( url ); - while ( i < curveLengths.length ) { + if ( cached !== undefined ) { - if ( curveLengths[ i ] >= d ) { + scope.manager.itemStart( url ); - var diff = curveLengths[ i ] - d; - var curve = this.curves[ i ]; + setTimeout( function () { - var segmentLength = curve.getLength(); - var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; + if ( onLoad ) { onLoad( cached ); } - return curve.getPointAt( u ); + scope.manager.itemEnd( url ); - } + }, 0 ); - i ++; + return cached; } - return null; + // Check if request is duplicate - // loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { + // Initialise array for duplicate requests - points.push( points[ 0 ] ); + loading[ url ] = []; - } + loading[ url ].push( { - return points; + onLoad: onLoad, + onProgress: onProgress, + onError: onError - }, + } ); - copy: function ( source ) { + request = new XMLHttpRequest(); - Curve.prototype.copy.call( this, source ); + request.open( 'GET', url, true ); - this.curves = []; + request.addEventListener( 'load', function ( event ) { - for ( var i = 0, l = source.curves.length; i < l; i ++ ) { + var response = this.response; - var curve = source.curves[ i ]; + var callbacks = loading[ url ]; - this.curves.push( curve.clone() ); + delete loading[ url ]; - } + if ( this.status === 200 || this.status === 0 ) { - this.autoClose = source.autoClose; + // Some browsers return HTTP Status 0 when using non-http protocol + // e.g. 'file://' or 'data://'. Handle as success. - return this; + 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 ); - toJSON: function () { + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { - var data = Curve.prototype.toJSON.call( this ); + var callback = callbacks[ i ]; + if ( callback.onLoad ) { callback.onLoad( response ); } - data.autoClose = this.autoClose; - data.curves = []; + } - for ( var i = 0, l = this.curves.length; i < l; i ++ ) { + scope.manager.itemEnd( url ); - var curve = this.curves[ i ]; - data.curves.push( curve.toJSON() ); + } else { - } + for ( var i$1 = 0, il$1 = callbacks.length; i$1 < il$1; i$1 ++ ) { - return data; + var callback$1 = callbacks[ i$1 ]; + if ( callback$1.onError ) { callback$1.onError( event ); } - }, + } - fromJSON: function ( json ) { + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - Curve.prototype.fromJSON.call( this, json ); + } - this.autoClose = json.autoClose; - this.curves = []; + }, false ); - for ( var i = 0, l = json.curves.length; i < l; i ++ ) { + request.addEventListener( 'progress', function ( event ) { - var curve = json.curves[ i ]; - this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); + var callbacks = loading[ url ]; - } + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { - return this; + var callback = callbacks[ i ]; + if ( callback.onProgress ) { callback.onProgress( event ); } - } + } - } ); + }, false ); - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Creates free form 2d path using series of points, lines or curves. - **/ + request.addEventListener( 'error', function ( event ) { - function Path( points ) { + var callbacks = loading[ url ]; - CurvePath.call( this ); + delete loading[ url ]; - this.type = 'Path'; + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { - this.currentPoint = new Vector2(); + var callback = callbacks[ i ]; + if ( callback.onError ) { callback.onError( event ); } - if ( points ) { + } - this.setFromPoints( points ); + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - } + }, false ); - } + request.addEventListener( 'abort', function ( event ) { - Path.prototype = Object.assign( Object.create( CurvePath.prototype ), { + var callbacks = loading[ url ]; - constructor: Path, + delete loading[ url ]; - setFromPoints: function ( points ) { + for ( var i = 0, il = callbacks.length; i < il; i ++ ) { - this.moveTo( points[ 0 ].x, points[ 0 ].y ); + var callback = callbacks[ i ]; + if ( callback.onError ) { callback.onError( event ); } - for ( var i = 1, l = points.length; i < l; i ++ ) { + } - this.lineTo( points[ i ].x, points[ i ].y ); + 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; } - moveTo: function ( x, y ) { + if ( request.overrideMimeType ) { request.overrideMimeType( this.mimeType !== undefined ? this.mimeType : 'text/plain' ); } - this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? + for ( var header in this.requestHeader ) { - }, + request.setRequestHeader( header, this.requestHeader[ header ] ); - lineTo: function ( x, y ) { + } - var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); - this.curves.push( curve ); + request.send( null ); - this.currentPoint.set( x, y ); + } - }, + scope.manager.itemStart( url ); - quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + return request; - var curve = new QuadraticBezierCurve( - this.currentPoint.clone(), - new Vector2( aCPx, aCPy ), - new Vector2( aX, aY ) - ); + }, - this.curves.push( curve ); + setResponseType: function ( value ) { - this.currentPoint.set( aX, aY ); + this.responseType = value; + return this; }, - bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - - var curve = new CubicBezierCurve( - this.currentPoint.clone(), - new Vector2( aCP1x, aCP1y ), - new Vector2( aCP2x, aCP2y ), - new Vector2( aX, aY ) - ); - - this.curves.push( curve ); + setWithCredentials: function ( value ) { - this.currentPoint.set( aX, aY ); + this.withCredentials = value; + return this; }, - splineThru: function ( pts /*Array of Vector*/ ) { - - var npts = [ this.currentPoint.clone() ].concat( pts ); + setMimeType: function ( value ) { - var curve = new SplineCurve( npts ); - this.curves.push( curve ); + this.mimeType = value; + return this; - this.currentPoint.copy( pts[ pts.length - 1 ] ); + } - }, + } ); - arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + function AnimationLoader( manager ) { - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; + Loader.call( this, manager ); - this.absarc( aX + x0, aY + y0, aRadius, - aStartAngle, aEndAngle, aClockwise ); + } - }, + AnimationLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { + constructor: AnimationLoader, - this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); + load: function ( url, onLoad, onProgress, onError ) { - }, + var scope = this; - ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + var loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.load( url, function ( text ) { - var x0 = this.currentPoint.x; - var y0 = this.currentPoint.y; + try { - this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + onLoad( scope.parse( JSON.parse( text ) ) ); - }, + } catch ( e ) { - absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { + if ( onError ) { - var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); + onError( e ); - if ( this.curves.length > 0 ) { + } else { - // if a previous curve is present, attempt to join - var firstPoint = curve.getPoint( 0 ); + console.error( e ); - if ( ! firstPoint.equals( this.currentPoint ) ) { + } - this.lineTo( firstPoint.x, firstPoint.y ); + scope.manager.itemError( url ); } - } - - this.curves.push( curve ); - - var lastPoint = curve.getPoint( 1 ); - this.currentPoint.copy( lastPoint ); + }, onProgress, onError ); }, - copy: function ( source ) { - - CurvePath.prototype.copy.call( this, source ); - - this.currentPoint.copy( source.currentPoint ); - - return this; + parse: function ( json ) { - }, + var animations = []; - toJSON: function () { + for ( var i = 0; i < json.length; i ++ ) { - var data = CurvePath.prototype.toJSON.call( this ); + var clip = AnimationClip.parse( json[ i ] ); - data.currentPoint = this.currentPoint.toArray(); + animations.push( clip ); - return data; + } - }, + return animations; - fromJSON: function ( json ) { + } - CurvePath.prototype.fromJSON.call( this, json ); + } ); - this.currentPoint.fromArray( json.currentPoint ); + /** + * Abstract Base class to block based textures loader (dds, pvr, ...) + * + * Sub classes have to implement the parse() method which will be used in load(). + */ - return this; + function CompressedTextureLoader( manager ) { - } + Loader.call( this, manager ); - } ); + } - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * Defines a 2d shape plane using paths. - **/ + CompressedTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - // STEP 1 Create a path. - // STEP 2 Turn path into shape. - // STEP 3 ExtrudeGeometry takes in Shape/Shapes - // STEP 3a - Extract points from each shape, turn to vertices - // STEP 3b - Triangulate each shape, add faces. + constructor: CompressedTextureLoader, - function Shape( points ) { + load: function ( url, onLoad, onProgress, onError ) { - Path.call( this, points ); + var scope = this; - this.uuid = _Math.generateUUID(); + var images = []; - this.type = 'Shape'; + var texture = new CompressedTexture(); + texture.image = images; - this.holes = []; + var loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); - } + var loaded = 0; - Shape.prototype = Object.assign( Object.create( Path.prototype ), { + function loadTexture( i ) { - constructor: Shape, + loader.load( url[ i ], function ( buffer ) { - getPointsHoles: function ( divisions ) { + var texDatas = scope.parse( buffer, true ); - var holesPts = []; + images[ i ] = { + width: texDatas.width, + height: texDatas.height, + format: texDatas.format, + mipmaps: texDatas.mipmaps + }; - for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + loaded += 1; - holesPts[ i ] = this.holes[ i ].getPoints( divisions ); + if ( loaded === 6 ) { - } + if ( texDatas.mipmapCount === 1 ) + { texture.minFilter = LinearFilter; } - return holesPts; + texture.format = texDatas.format; + texture.needsUpdate = true; - }, + if ( onLoad ) { onLoad( texture ); } - // get points of shape and holes (keypoints based on segments parameter) + } - extractPoints: function ( divisions ) { + }, onProgress, onError ); - return { + } - shape: this.getPoints( divisions ), - holes: this.getPointsHoles( divisions ) + if ( Array.isArray( url ) ) { - }; + for ( var i = 0, il = url.length; i < il; ++ i ) { - }, + loadTexture( i ); - copy: function ( source ) { + } - Path.prototype.copy.call( this, source ); + } else { - this.holes = []; + // compressed cubemap texture stored in a single DDS file - for ( var i = 0, l = source.holes.length; i < l; i ++ ) { + loader.load( url, function ( buffer ) { - var hole = source.holes[ i ]; + var texDatas = scope.parse( buffer, true ); - this.holes.push( hole.clone() ); + if ( texDatas.isCubemap ) { - } + var faces = texDatas.mipmaps.length / texDatas.mipmapCount; - return this; + for ( var f = 0; f < faces; f ++ ) { - }, + images[ f ] = { mipmaps: [] }; - toJSON: function () { + for ( var i = 0; i < texDatas.mipmapCount; i ++ ) { - var data = Path.prototype.toJSON.call( this ); + 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; - data.uuid = this.uuid; - data.holes = []; + } - for ( var i = 0, l = this.holes.length; i < l; i ++ ) { + } - var hole = this.holes[ i ]; - data.holes.push( hole.toJSON() ); + } else { - } + texture.image.width = texDatas.width; + texture.image.height = texDatas.height; + texture.mipmaps = texDatas.mipmaps; - return data; + } - }, + if ( texDatas.mipmapCount === 1 ) { - fromJSON: function ( json ) { + texture.minFilter = LinearFilter; - Path.prototype.fromJSON.call( this, json ); + } - this.uuid = json.uuid; - this.holes = []; + texture.format = texDatas.format; + texture.needsUpdate = true; - for ( var i = 0, l = json.holes.length; i < l; i ++ ) { + if ( onLoad ) { onLoad( texture ); } - var hole = json.holes[ i ]; - this.holes.push( new Path().fromJSON( hole ) ); + }, onProgress, onError ); } - return this; + return texture; } } ); /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ + * 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(). */ - function Light( color, intensity ) { - - Object3D.call( this ); - - this.type = 'Light'; - - this.color = new Color( color ); - this.intensity = intensity !== undefined ? intensity : 1; + function DataTextureLoader( manager ) { - this.receiveShadow = undefined; + Loader.call( this, manager ); } - Light.prototype = Object.assign( Object.create( Object3D.prototype ), { + DataTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - constructor: Light, + constructor: DataTextureLoader, - isLight: true, + load: function ( url, onLoad, onProgress, onError ) { - copy: function ( source ) { + var scope = this; - Object3D.prototype.copy.call( this, source ); + var texture = new DataTexture(); - this.color.copy( source.color ); - this.intensity = source.intensity; + var loader = new FileLoader( this.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setRequestHeader( this.requestHeader ); + loader.setPath( this.path ); + loader.load( url, function ( buffer ) { - return this; + var texData = scope.parse( buffer ); - }, + if ( ! texData ) { return; } - toJSON: function ( meta ) { + if ( texData.image !== undefined ) { - var data = Object3D.prototype.toJSON.call( this, meta ); + texture.image = texData.image; - data.object.color = this.color.getHex(); - data.object.intensity = this.intensity; + } else if ( texData.data !== undefined ) { - if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); + texture.image.width = texData.width; + texture.image.height = texData.height; + texture.image.data = texData.data; - 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(); + texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; + texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; - return data; + 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.format !== undefined ) { - /** - * @author alteredq / http://alteredqualia.com/ - */ + texture.format = texData.format; - function HemisphereLight( skyColor, groundColor, intensity ) { + } - Light.call( this, skyColor, intensity ); + if ( texData.type !== undefined ) { - this.type = 'HemisphereLight'; + texture.type = texData.type; - this.castShadow = undefined; + } - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + if ( texData.mipmaps !== undefined ) { - this.groundColor = new Color( groundColor ); + texture.mipmaps = texData.mipmaps; + texture.minFilter = LinearMipmapLinearFilter; // presumably... - } + } - HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { + if ( texData.mipmapCount === 1 ) { - constructor: HemisphereLight, + texture.minFilter = LinearFilter; - isHemisphereLight: true, + } - copy: function ( source ) { + texture.needsUpdate = true; - Light.prototype.copy.call( this, source ); + if ( onLoad ) { onLoad( texture, texData ); } - this.groundColor.copy( source.groundColor ); + }, onProgress, onError ); - return this; + + return texture; } } ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + function ImageLoader( manager ) { - function LightShadow( camera ) { + Loader.call( this, manager ); - this.camera = camera; + } - this.bias = 0; - this.radius = 1; + ImageLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - this.mapSize = new Vector2( 512, 512 ); + constructor: ImageLoader, - this.map = null; - this.matrix = new Matrix4(); + load: function ( url, onLoad, onProgress, onError ) { - } + if ( this.path !== undefined ) { url = this.path + url; } - Object.assign( LightShadow.prototype, { + url = this.manager.resolveURL( url ); - copy: function ( source ) { + var scope = this; - this.camera = source.camera.clone(); + var cached = Cache.get( url ); - this.bias = source.bias; - this.radius = source.radius; + if ( cached !== undefined ) { - this.mapSize.copy( source.mapSize ); + scope.manager.itemStart( url ); - return this; + setTimeout( function () { - }, + if ( onLoad ) { onLoad( cached ); } - clone: function () { + scope.manager.itemEnd( url ); - return new this.constructor().copy( this ); + }, 0 ); - }, + return cached; - toJSON: function () { + } - var object = {}; + var image = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'img' ); - if ( this.bias !== 0 ) object.bias = this.bias; - if ( this.radius !== 1 ) object.radius = this.radius; - if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); + function onImageLoad() { - object.camera = this.camera.toJSON( false ).object; - delete object.camera.matrix; + image.removeEventListener( 'load', onImageLoad, false ); + image.removeEventListener( 'error', onImageError, false ); - return object; + Cache.add( url, this ); - } + if ( onLoad ) { onLoad( this ); } - } ); + scope.manager.itemEnd( url ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function SpotLightShadow() { + function onImageError( event ) { - LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); + image.removeEventListener( 'load', onImageLoad, false ); + image.removeEventListener( 'error', onImageError, false ); - } + if ( onError ) { onError( event ); } - SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - constructor: SpotLightShadow, + } - isSpotLightShadow: true, + image.addEventListener( 'load', onImageLoad, false ); + image.addEventListener( 'error', onImageError, false ); - update: function ( light ) { + if ( url.substr( 0, 5 ) !== 'data:' ) { - var camera = this.camera; + if ( this.crossOrigin !== undefined ) { image.crossOrigin = this.crossOrigin; } - var fov = _Math.RAD2DEG * 2 * light.angle; - var aspect = this.mapSize.width / this.mapSize.height; - var far = light.distance || camera.far; + } - if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { + scope.manager.itemStart( url ); - camera.fov = fov; - camera.aspect = aspect; - camera.far = far; - camera.updateProjectionMatrix(); + image.src = url; - } + return image; } } ); - /** - * @author alteredq / http://alteredqualia.com/ - */ + function CubeTextureLoader( manager ) { - function SpotLight( color, intensity, distance, angle, penumbra, decay ) { + Loader.call( this, manager ); - Light.call( this, color, intensity ); + } - this.type = 'SpotLight'; + CubeTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + constructor: CubeTextureLoader, - this.target = new Object3D(); + load: function ( urls, onLoad, onProgress, onError ) { - Object.defineProperty( this, 'power', { - get: function () { + var texture = new CubeTexture(); - // intensity = power per solid angle. - // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf - return this.intensity * Math.PI; + var loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); - }, - set: function ( power ) { + var loaded = 0; - // intensity = power per solid angle. - // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf - this.intensity = power / Math.PI; + function loadTexture( i ) { - } - } ); + loader.load( urls[ i ], function ( image ) { - this.distance = ( distance !== undefined ) ? distance : 0; - this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; - this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + texture.images[ i ] = image; - this.shadow = new SpotLightShadow(); + loaded ++; - } + if ( loaded === 6 ) { - SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { + texture.needsUpdate = true; - constructor: SpotLight, + if ( onLoad ) { onLoad( texture ); } - isSpotLight: true, + } - copy: function ( source ) { + }, undefined, onError ); - Light.prototype.copy.call( this, source ); + } - this.distance = source.distance; - this.angle = source.angle; - this.penumbra = source.penumbra; - this.decay = source.decay; + for ( var i = 0; i < urls.length; ++ i ) { - this.target = source.target.clone(); + loadTexture( i ); - this.shadow = source.shadow.clone(); + } - return this; + return texture; } } ); - /** - * @author mrdoob / http://mrdoob.com/ - */ - + function TextureLoader( manager ) { - function PointLight( color, intensity, distance, decay ) { + Loader.call( this, manager ); - Light.call( this, color, intensity ); + } - this.type = 'PointLight'; + TextureLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - Object.defineProperty( this, 'power', { - get: function () { + constructor: TextureLoader, - // intensity = power per solid angle. - // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf - return this.intensity * 4 * Math.PI; + load: function ( url, onLoad, onProgress, onError ) { - }, - set: function ( power ) { + var texture = new Texture(); - // intensity = power per solid angle. - // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf - this.intensity = power / ( 4 * Math.PI ); + var loader = new ImageLoader( this.manager ); + loader.setCrossOrigin( this.crossOrigin ); + loader.setPath( this.path ); - } - } ); + loader.load( url, function ( image ) { - this.distance = ( distance !== undefined ) ? distance : 0; - this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + texture.image = image; - this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); + // JPEGs can't have an alpha channel, so memory can be saved by storing them as RGB. + var isJPEG = url.search( /\.jpe?g($|\?)/i ) > 0 || url.search( /^data\:image\/jpeg/ ) === 0; - } - - PointLight.prototype = Object.assign( Object.create( Light.prototype ), { - - constructor: PointLight, - - isPointLight: true, + texture.format = isJPEG ? RGBFormat : RGBAFormat; + texture.needsUpdate = true; - copy: function ( source ) { + if ( onLoad !== undefined ) { - Light.prototype.copy.call( this, source ); + onLoad( texture ); - this.distance = source.distance; - this.decay = source.decay; + } - this.shadow = source.shadow.clone(); + }, onProgress, onError ); - return this; + return texture; } } ); /** - * @author alteredq / http://alteredqualia.com/ - * @author arose / http://github.com/arose - */ - - function OrthographicCamera( left, right, top, bottom, near, far ) { - - Camera.call( this ); - - this.type = 'OrthographicCamera'; - - this.zoom = 1; - this.view = null; + * 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. + * + **/ - this.left = ( left !== undefined ) ? left : - 1; - this.right = ( right !== undefined ) ? right : 1; - this.top = ( top !== undefined ) ? top : 1; - this.bottom = ( bottom !== undefined ) ? bottom : - 1; + function Curve() { - this.near = ( near !== undefined ) ? near : 0.1; - this.far = ( far !== undefined ) ? far : 2000; + this.type = 'Curve'; - this.updateProjectionMatrix(); + this.arcLengthDivisions = 200; } - OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), { - - constructor: OrthographicCamera, - - isOrthographicCamera: true, - - copy: function ( source, recursive ) { - - Camera.prototype.copy.call( this, source, recursive ); + Object.assign( Curve.prototype, { - this.left = source.left; - this.right = source.right; - this.top = source.top; - this.bottom = source.bottom; - this.near = source.near; - this.far = source.far; + // Virtual base class method to overwrite and implement in subclasses + // - t [0 .. 1] - this.zoom = source.zoom; - this.view = source.view === null ? null : Object.assign( {}, source.view ); + getPoint: function ( /* t, optionalTarget */ ) { - return this; + console.warn( 'THREE.Curve: .getPoint() not implemented.' ); + return null; }, - setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) { + // Get point at relative position in curve according to arc length + // - u [0 .. 1] - if ( this.view === null ) { + getPointAt: function ( u, optionalTarget ) { - this.view = { - enabled: true, - fullWidth: 1, - fullHeight: 1, - offsetX: 0, - offsetY: 0, - width: 1, - height: 1 - }; + var t = this.getUtoTmapping( u ); + return this.getPoint( t, optionalTarget ); - } + }, - 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; + // Get sequence of points using getPoint( t ) - this.updateProjectionMatrix(); + getPoints: function ( divisions ) { - }, + if ( divisions === undefined ) { divisions = 5; } - clearViewOffset: function () { + var points = []; - if ( this.view !== null ) { + for ( var d = 0; d <= divisions; d ++ ) { - this.view.enabled = false; + points.push( this.getPoint( d / divisions ) ); } - this.updateProjectionMatrix(); + return points; }, - updateProjectionMatrix: function () { + // Get sequence of points using getPointAt( u ) - var dx = ( this.right - this.left ) / ( 2 * this.zoom ); - var dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); - var cx = ( this.right + this.left ) / 2; - var cy = ( this.top + this.bottom ) / 2; + getSpacedPoints: function ( divisions ) { - var left = cx - dx; - var right = cx + dx; - var top = cy + dy; - var bottom = cy - dy; + if ( divisions === undefined ) { divisions = 5; } - if ( this.view !== null && this.view.enabled ) { + var points = []; - var zoomW = this.zoom / ( this.view.width / this.view.fullWidth ); - var zoomH = this.zoom / ( this.view.height / this.view.fullHeight ); - var scaleW = ( this.right - this.left ) / this.view.width; - var scaleH = ( this.top - this.bottom ) / this.view.height; + for ( var d = 0; d <= divisions; d ++ ) { - left += scaleW * ( this.view.offsetX / zoomW ); - right = left + scaleW * ( this.view.width / zoomW ); - top -= scaleH * ( this.view.offsetY / zoomH ); - bottom = top - scaleH * ( this.view.height / zoomH ); + points.push( this.getPointAt( d / divisions ) ); } - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); - - this.projectionMatrixInverse.getInverse( this.projectionMatrix ); + return points; }, - toJSON: function ( meta ) { - - var data = Object3D.prototype.toJSON.call( this, meta ); + // Get total curve arc length - 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; + getLength: function () { - if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); + var lengths = this.getLengths(); + return lengths[ lengths.length - 1 ]; - return data; + }, - } + // Get list of cumulative segment lengths - } ); + getLengths: function ( divisions ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + if ( divisions === undefined ) { divisions = this.arcLengthDivisions; } - function DirectionalLightShadow( ) { + if ( this.cacheArcLengths && + ( this.cacheArcLengths.length === divisions + 1 ) && + ! this.needsUpdate ) { - LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); + return this.cacheArcLengths; - } + } - DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { + this.needsUpdate = false; - constructor: DirectionalLightShadow + var cache = []; + var current, last = this.getPoint( 0 ); + var sum = 0; - } ); + cache.push( 0 ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + for ( var p = 1; p <= divisions; p ++ ) { - function DirectionalLight( color, intensity ) { + current = this.getPoint( p / divisions ); + sum += current.distanceTo( last ); + cache.push( sum ); + last = current; - Light.call( this, color, intensity ); + } - this.type = 'DirectionalLight'; + this.cacheArcLengths = cache; - this.position.copy( Object3D.DefaultUp ); - this.updateMatrix(); + return cache; // { sums: cache, sum: sum }; Sum is in the last element. - this.target = new Object3D(); + }, - this.shadow = new DirectionalLightShadow(); + updateArcLengths: function () { - } + this.needsUpdate = true; + this.getLengths(); - DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { + }, - constructor: DirectionalLight, + // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant - isDirectionalLight: true, + getUtoTmapping: function ( u, distance ) { - copy: function ( source ) { + var arcLengths = this.getLengths(); - Light.prototype.copy.call( this, source ); + var i = 0, il = arcLengths.length; - this.target = source.target.clone(); + var targetArcLength; // The targeted u distance value to get - this.shadow = source.shadow.clone(); + if ( distance ) { - return this; + targetArcLength = distance; - } + } else { - } ); + targetArcLength = u * arcLengths[ il - 1 ]; - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function AmbientLight( color, intensity ) { + // binary search for the index with largest value smaller than target u distance - Light.call( this, color, intensity ); + var low = 0, high = il - 1, comparison; - this.type = 'AmbientLight'; + while ( low <= high ) { - this.castShadow = undefined; + i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - } + comparison = arcLengths[ i ] - targetArcLength; - AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { + if ( comparison < 0 ) { - constructor: AmbientLight, + low = i + 1; - isAmbientLight: true + } else if ( comparison > 0 ) { - } ); + high = i - 1; - /** - * @author abelnation / http://github.com/abelnation - */ + } else { - function RectAreaLight( color, intensity, width, height ) { + high = i; + break; - Light.call( this, color, intensity ); + // DONE - this.type = 'RectAreaLight'; + } - this.width = ( width !== undefined ) ? width : 10; - this.height = ( height !== undefined ) ? height : 10; + } - } + i = high; - RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { + if ( arcLengths[ i ] === targetArcLength ) { - constructor: RectAreaLight, + return i / ( il - 1 ); - isRectAreaLight: true, + } - copy: function ( source ) { + // we could get finer grain at lengths, or use simple interpolation between two points - Light.prototype.copy.call( this, source ); + var lengthBefore = arcLengths[ i ]; + var lengthAfter = arcLengths[ i + 1 ]; - this.width = source.width; - this.height = source.height; + var segmentLength = lengthAfter - lengthBefore; - return this; + // determine where we are between the 'before' and 'after' points - }, + var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; - toJSON: function ( meta ) { + // add that fractional amount to t - var data = Light.prototype.toJSON.call( this, meta ); + var t = ( i + segmentFraction ) / ( il - 1 ); - data.object.width = this.width; - data.object.height = this.height; + return t; - return data; + }, - } + // 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: function ( t, optionalTarget ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + var delta = 0.0001; + var t1 = t - delta; + var t2 = t + delta; - function MaterialLoader( manager ) { + // Capping in case of danger - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.textures = {}; + if ( t1 < 0 ) { t1 = 0; } + if ( t2 > 1 ) { t2 = 1; } - } + var pt1 = this.getPoint( t1 ); + var pt2 = this.getPoint( t2 ); - Object.assign( MaterialLoader.prototype, { + var tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); - load: function ( url, onLoad, onProgress, onError ) { + tangent.copy( pt2 ).sub( pt1 ).normalize(); - var scope = this; + return tangent; - var loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.load( url, function ( text ) { + }, - onLoad( scope.parse( JSON.parse( text ) ) ); + getTangentAt: function ( u, optionalTarget ) { - }, onProgress, onError ); + var t = this.getUtoTmapping( u ); + return this.getTangent( t, optionalTarget ); }, - parse: function ( json ) { + computeFrenetFrames: function ( segments, closed ) { - var textures = this.textures; + // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf - function getTexture( name ) { + var normal = new Vector3(); - if ( textures[ name ] === undefined ) { + var tangents = []; + var normals = []; + var binormals = []; - console.warn( 'THREE.MaterialLoader: Undefined texture', name ); + var vec = new Vector3(); + var mat = new Matrix4(); - } + // compute the tangent vectors for each segment on the curve - return textures[ name ]; + for ( var i = 0; i <= segments; i ++ ) { - } + var u = i / segments; - var material = new Materials[ json.type ](); + tangents[ i ] = this.getTangentAt( u, new Vector3() ); + tangents[ i ].normalize(); - if ( json.uuid !== undefined ) material.uuid = json.uuid; - if ( json.name !== undefined ) material.name = json.name; - if ( json.color !== undefined ) material.color.setHex( json.color ); - if ( json.roughness !== undefined ) material.roughness = json.roughness; - if ( json.metalness !== undefined ) material.metalness = json.metalness; - if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); - if ( json.specular !== undefined ) material.specular.setHex( json.specular ); - if ( json.shininess !== undefined ) material.shininess = json.shininess; - if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat; - if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness; - if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; - if ( json.fog !== undefined ) material.fog = json.fog; - if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; - if ( json.blending !== undefined ) material.blending = json.blending; - if ( json.combine !== undefined ) material.combine = json.combine; - if ( json.side !== undefined ) material.side = json.side; - if ( json.opacity !== undefined ) material.opacity = json.opacity; - if ( json.transparent !== undefined ) material.transparent = json.transparent; - if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; - if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; - if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; - if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; - if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; - if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; - if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; - if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; - - 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.skinning !== undefined ) material.skinning = json.skinning; - if ( json.morphTargets !== undefined ) material.morphTargets = json.morphTargets; - if ( json.dithering !== undefined ) material.dithering = json.dithering; - - if ( json.visible !== undefined ) material.visible = json.visible; - if ( json.userData !== undefined ) material.userData = json.userData; + } - // Shader Material + // select an initial normal vector perpendicular to the first tangent vector, + // and in the direction of the minimum tangent xyz component - if ( json.uniforms !== undefined ) { + normals[ 0 ] = new Vector3(); + binormals[ 0 ] = new Vector3(); + var min = Number.MAX_VALUE; + var tx = Math.abs( tangents[ 0 ].x ); + var ty = Math.abs( tangents[ 0 ].y ); + var tz = Math.abs( tangents[ 0 ].z ); - for ( var name in json.uniforms ) { + if ( tx <= min ) { - var uniform = json.uniforms[ name ]; + min = tx; + normal.set( 1, 0, 0 ); - material.uniforms[ name ] = {}; + } - switch ( uniform.type ) { + if ( ty <= min ) { - case 't': - material.uniforms[ name ].value = getTexture( uniform.value ); - break; + min = ty; + normal.set( 0, 1, 0 ); - case 'c': - material.uniforms[ name ].value = new Color().setHex( uniform.value ); - break; + } - case 'v2': - material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); - break; + if ( tz <= min ) { - case 'v3': - material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); - break; + normal.set( 0, 0, 1 ); - case 'v4': - material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); - break; + } - case 'm4': - material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); - break; + vec.crossVectors( tangents[ 0 ], normal ).normalize(); - default: - material.uniforms[ name ].value = uniform.value; + 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 ( var i$1 = 1; i$1 <= segments; i$1 ++ ) { - if ( json.defines !== undefined ) material.defines = json.defines; - if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; - if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; + normals[ i$1 ] = normals[ i$1 - 1 ].clone(); - // Deprecated + binormals[ i$1 ] = binormals[ i$1 - 1 ].clone(); - if ( json.shading !== undefined ) material.flatShading = json.shading === 1; // THREE.FlatShading + vec.crossVectors( tangents[ i$1 - 1 ], tangents[ i$1 ] ); - // for PointsMaterial + if ( vec.length() > Number.EPSILON ) { - if ( json.size !== undefined ) material.size = json.size; - if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; + vec.normalize(); - // maps + var theta = Math.acos( MathUtils.clamp( tangents[ i$1 - 1 ].dot( tangents[ i$1 ] ), - 1, 1 ) ); // clamp for floating pt errors - if ( json.map !== undefined ) material.map = getTexture( json.map ); + normals[ i$1 ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); - if ( json.alphaMap !== undefined ) { + } - material.alphaMap = getTexture( json.alphaMap ); - material.transparent = true; + binormals[ i$1 ].crossVectors( tangents[ i$1 ], normals[ i$1 ] ); } - 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 ) { + // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same - var normalScale = json.normalScale; + if ( closed === true ) { - if ( Array.isArray( normalScale ) === false ) { + var theta$1 = Math.acos( MathUtils.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); + theta$1 /= segments; - // Blender exporter used to export a scalar. See #7459 + if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { - normalScale = [ normalScale, normalScale ]; + theta$1 = - theta$1; } - material.normalScale = new Vector2().fromArray( normalScale ); + for ( var i$2 = 1; i$2 <= segments; i$2 ++ ) { - } + // twist a little... + normals[ i$2 ].applyMatrix4( mat.makeRotationAxis( tangents[ i$2 ], theta$1 * i$2 ) ); + binormals[ i$2 ].crossVectors( tangents[ i$2 ], normals[ i$2 ] ); - 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; + return { + tangents: tangents, + normals: normals, + binormals: binormals + }; - if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); + }, - if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); - if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; + clone: function () { - if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; + return new this.constructor().copy( this ); - 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; + copy: function ( source ) { - if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); + this.arcLengthDivisions = source.arcLengthDivisions; - return material; + return this; }, - setPath: function ( value ) { + toJSON: function () { + + var data = { + metadata: { + version: 4.5, + type: 'Curve', + generator: 'Curve.toJSON' + } + }; + + data.arcLengthDivisions = this.arcLengthDivisions; + data.type = this.type; - this.path = value; - return this; + return data; }, - setTextures: function ( value ) { + fromJSON: function ( json ) { + + this.arcLengthDivisions = json.arcLengthDivisions; - this.textures = value; return this; } } ); - /** - * @author Don McCurdy / https://www.donmccurdy.com - */ + function EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - var LoaderUtils = { + Curve.call( this ); - decodeText: function ( array ) { + this.type = 'EllipseCurve'; - if ( typeof TextDecoder !== 'undefined' ) { + this.aX = aX || 0; + this.aY = aY || 0; - return new TextDecoder().decode( array ); + this.xRadius = xRadius || 1; + this.yRadius = yRadius || 1; - } + this.aStartAngle = aStartAngle || 0; + this.aEndAngle = aEndAngle || 2 * Math.PI; - // Avoid the String.fromCharCode.apply(null, array) shortcut, which - // throws a "maximum call stack size exceeded" error for large arrays. + this.aClockwise = aClockwise || false; - var s = ''; + this.aRotation = aRotation || 0; - for ( var i = 0, il = array.length; i < il; i ++ ) { + } - // Implicitly assumes little-endian. - s += String.fromCharCode( array[ i ] ); + EllipseCurve.prototype = Object.create( Curve.prototype ); + EllipseCurve.prototype.constructor = EllipseCurve; - } + EllipseCurve.prototype.isEllipseCurve = true; - // Merges multi-byte utf-8 characters. - return decodeURIComponent( escape( s ) ); + EllipseCurve.prototype.getPoint = function ( t, optionalTarget ) { - }, + var point = optionalTarget || new Vector2(); - extractUrlBase: function ( url ) { + var twoPi = Math.PI * 2; + var deltaAngle = this.aEndAngle - this.aStartAngle; + var samePoints = Math.abs( deltaAngle ) < Number.EPSILON; - var index = url.lastIndexOf( '/' ); + // ensures that deltaAngle is 0 .. 2 PI + while ( deltaAngle < 0 ) { deltaAngle += twoPi; } + while ( deltaAngle > twoPi ) { deltaAngle -= twoPi; } - if ( index === - 1 ) return './'; + if ( deltaAngle < Number.EPSILON ) { - return url.substr( 0, index + 1 ); + if ( samePoints ) { - } + deltaAngle = 0; - }; + } else { - /** - * @author mrdoob / http://mrdoob.com/ - */ + deltaAngle = twoPi; - function BufferGeometryLoader( manager ) { + } - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + } - } + if ( this.aClockwise === true && ! samePoints ) { - Object.assign( BufferGeometryLoader.prototype, { + if ( deltaAngle === twoPi ) { - load: function ( url, onLoad, onProgress, onError ) { + deltaAngle = - twoPi; - var scope = this; + } else { - var loader = new FileLoader( scope.manager ); - loader.setPath( scope.path ); - loader.load( url, function ( text ) { + deltaAngle = deltaAngle - twoPi; - onLoad( scope.parse( JSON.parse( text ) ) ); + } - }, onProgress, onError ); + } - }, + var angle = this.aStartAngle + t * deltaAngle; + var x = this.aX + this.xRadius * Math.cos( angle ); + var y = this.aY + this.yRadius * Math.sin( angle ); - parse: function ( json ) { + if ( this.aRotation !== 0 ) { - var geometry = new BufferGeometry(); + var cos = Math.cos( this.aRotation ); + var sin = Math.sin( this.aRotation ); - var index = json.data.index; + var tx = x - this.aX; + var ty = y - this.aY; - if ( index !== undefined ) { + // Rotate the point about the center of the ellipse. + x = tx * cos - ty * sin + this.aX; + y = tx * sin + ty * cos + this.aY; - var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); - geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); + } - } + return point.set( x, y ); - var attributes = json.data.attributes; + }; - for ( var key in attributes ) { + EllipseCurve.prototype.copy = function ( source ) { - var attribute = attributes[ key ]; - var typedArray = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); + Curve.prototype.copy.call( this, source ); - geometry.addAttribute( key, new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ) ); + this.aX = source.aX; + this.aY = source.aY; - } + this.xRadius = source.xRadius; + this.yRadius = source.yRadius; - var groups = json.data.groups || json.data.drawcalls || json.data.offsets; + this.aStartAngle = source.aStartAngle; + this.aEndAngle = source.aEndAngle; - if ( groups !== undefined ) { + this.aClockwise = source.aClockwise; - for ( var i = 0, n = groups.length; i !== n; ++ i ) { + this.aRotation = source.aRotation; - var group = groups[ i ]; + return this; - geometry.addGroup( group.start, group.count, group.materialIndex ); + }; - } - } + EllipseCurve.prototype.toJSON = function () { - var boundingSphere = json.data.boundingSphere; + var data = Curve.prototype.toJSON.call( this ); - if ( boundingSphere !== undefined ) { + data.aX = this.aX; + data.aY = this.aY; - var center = new Vector3(); + data.xRadius = this.xRadius; + data.yRadius = this.yRadius; - if ( boundingSphere.center !== undefined ) { + data.aStartAngle = this.aStartAngle; + data.aEndAngle = this.aEndAngle; - center.fromArray( boundingSphere.center ); + data.aClockwise = this.aClockwise; - } + data.aRotation = this.aRotation; - geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); + return data; - } + }; - return geometry; + EllipseCurve.prototype.fromJSON = function ( json ) { - }, + Curve.prototype.fromJSON.call( this, json ); - setPath: function ( value ) { + this.aX = json.aX; + this.aY = json.aY; - this.path = value; - return this; + this.xRadius = json.xRadius; + this.yRadius = json.yRadius; - } + this.aStartAngle = json.aStartAngle; + this.aEndAngle = json.aEndAngle; - } ); + this.aClockwise = json.aClockwise; - var TYPED_ARRAYS = { - Int8Array: Int8Array, - Uint8Array: Uint8Array, - // Workaround for IE11 pre KB2929437. See #11440 - Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, - Int16Array: Int16Array, - Uint16Array: Uint16Array, - Int32Array: Int32Array, - Uint32Array: Uint32Array, - Float32Array: Float32Array, - Float64Array: Float64Array - }; + this.aRotation = json.aRotation; - /** - * @author alteredq / http://alteredqualia.com/ - */ + return this; - function Loader() {} + }; - Loader.Handlers = { + function ArcCurve( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - handlers: [], + EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - add: function ( regex, loader ) { + this.type = 'ArcCurve'; - this.handlers.push( regex, loader ); + } - }, + ArcCurve.prototype = Object.create( EllipseCurve.prototype ); + ArcCurve.prototype.constructor = ArcCurve; - get: function ( file ) { + ArcCurve.prototype.isArcCurve = true; - var handlers = this.handlers; + /** + * 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 + */ - for ( var i = 0, l = handlers.length; i < l; i += 2 ) { - var regex = handlers[ i ]; - var loader = handlers[ i + 1 ]; + /* + 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 - if ( regex.test( file ) ) { + 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. + */ - return loader; + function CubicPoly() { - } + var c0 = 0, c1 = 0, c2 = 0, c3 = 0; - } + /* + * Compute coefficients for a cubic polynomial + * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 + * such that + * p(0) = x0, p(1) = x1 + * and + * p'(0) = t0, p'(1) = t1. + */ + function init( x0, x1, t0, t1 ) { - return null; + c0 = x0; + c1 = t0; + c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; + c3 = 2 * x0 - 2 * x1 + t0 + t1; } - }; + return { - Object.assign( Loader.prototype, { + initCatmullRom: function ( x0, x1, x2, x3, tension ) { - crossOrigin: 'anonymous', + init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); - onLoadStart: function () {}, + }, - onLoadProgress: function () {}, + initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { - onLoadComplete: function () {}, + // compute tangents when parameterized in [t1,t2] + var t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; + var t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; - initMaterials: function ( materials, texturePath, crossOrigin ) { + // rescale tangents for parametrization in [0,1] + t1 *= dt1; + t2 *= dt1; - var array = []; + init( x1, x2, t1, t2 ); - for ( var i = 0; i < materials.length; ++ i ) { + }, + + calc: function ( t ) { - array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin ); + var t2 = t * t; + var t3 = t2 * t; + return c0 + c1 * t + c2 * t2 + c3 * t3; } - return array; + }; - }, + } - createMaterial: ( function () { + // - var BlendingMode = { - NoBlending: NoBlending, - NormalBlending: NormalBlending, - AdditiveBlending: AdditiveBlending, - SubtractiveBlending: SubtractiveBlending, - MultiplyBlending: MultiplyBlending, - CustomBlending: CustomBlending - }; + var tmp = new Vector3(); + var px = new CubicPoly(), py = new CubicPoly(), pz = new CubicPoly(); - var color = new Color(); - var textureLoader = new TextureLoader(); - var materialLoader = new MaterialLoader(); + function CatmullRomCurve3( points, closed, curveType, tension ) { - return function createMaterial( m, texturePath, crossOrigin ) { + Curve.call( this ); - // convert from old material format + this.type = 'CatmullRomCurve3'; - var textures = {}; + this.points = points || []; + this.closed = closed || false; + this.curveType = curveType || 'centripetal'; + this.tension = ( tension !== undefined ) ? tension : 0.5; - function loadTexture( path, repeat, offset, wrap, anisotropy ) { + } - var fullPath = texturePath + path; - var loader = Loader.Handlers.get( fullPath ); + CatmullRomCurve3.prototype = Object.create( Curve.prototype ); + CatmullRomCurve3.prototype.constructor = CatmullRomCurve3; - var texture; + CatmullRomCurve3.prototype.isCatmullRomCurve3 = true; - if ( loader !== null ) { + CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) { - texture = loader.load( fullPath ); + var point = optionalTarget || new Vector3(); - } else { + var points = this.points; + var l = points.length; - textureLoader.setCrossOrigin( crossOrigin ); - texture = textureLoader.load( fullPath ); + var p = ( l - ( this.closed ? 0 : 1 ) ) * t; + var intPoint = Math.floor( p ); + var weight = p - intPoint; - } + if ( this.closed ) { - if ( repeat !== undefined ) { + intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; - texture.repeat.fromArray( repeat ); + } else if ( weight === 0 && intPoint === l - 1 ) { - if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping; - if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping; + intPoint = l - 2; + weight = 1; - } + } - if ( offset !== undefined ) { + var p0, p1, p2, p3; // 4 points - texture.offset.fromArray( offset ); + if ( this.closed || intPoint > 0 ) { - } + p0 = points[ ( intPoint - 1 ) % l ]; - if ( wrap !== undefined ) { + } else { - if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping; - if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping; + // extrapolate first point + tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); + p0 = tmp; - if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping; - if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping; + } - } + p1 = points[ intPoint % l ]; + p2 = points[ ( intPoint + 1 ) % l ]; - if ( anisotropy !== undefined ) { + if ( this.closed || intPoint + 2 < l ) { - texture.anisotropy = anisotropy; + p3 = points[ ( intPoint + 2 ) % l ]; - } + } else { - var uuid = _Math.generateUUID(); + // extrapolate last point + tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); + p3 = tmp; - textures[ uuid ] = texture; + } - return uuid; + if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { - } + // init Centripetal / Chordal Catmull-Rom + var pow = this.curveType === 'chordal' ? 0.5 : 0.25; + var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); + var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); + var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); - // + // safety check for repeated points + if ( dt1 < 1e-4 ) { dt1 = 1.0; } + if ( dt0 < 1e-4 ) { dt0 = dt1; } + if ( dt2 < 1e-4 ) { dt2 = dt1; } - var json = { - uuid: _Math.generateUUID(), - type: 'MeshLambertMaterial' - }; + px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); + py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); + pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); - for ( var name in m ) { + } else if ( this.curveType === 'catmullrom' ) { - var value = m[ name ]; + 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 ); - switch ( name ) { + } - case 'DbgColor': - case 'DbgIndex': - case 'opticalDensity': - case 'illumination': - break; - case 'DbgName': - json.name = value; - break; - case 'blending': - json.blending = BlendingMode[ value ]; - break; - case 'colorAmbient': - case 'mapAmbient': - console.warn( 'THREE.Loader.createMaterial:', name, 'is no longer supported.' ); - break; - case 'colorDiffuse': - json.color = color.fromArray( value ).getHex(); - break; - case 'colorSpecular': - json.specular = color.fromArray( value ).getHex(); - break; - case 'colorEmissive': - json.emissive = color.fromArray( value ).getHex(); - break; - case 'specularCoef': - json.shininess = value; - break; - case 'shading': - if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial'; - if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial'; - if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial'; - break; - case 'mapDiffuse': - json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); - break; - case 'mapDiffuseRepeat': - case 'mapDiffuseOffset': - case 'mapDiffuseWrap': - case 'mapDiffuseAnisotropy': - break; - case 'mapEmissive': - json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy ); - break; - case 'mapEmissiveRepeat': - case 'mapEmissiveOffset': - case 'mapEmissiveWrap': - case 'mapEmissiveAnisotropy': - break; - case 'mapLight': - json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); - break; - case 'mapLightRepeat': - case 'mapLightOffset': - case 'mapLightWrap': - case 'mapLightAnisotropy': - break; - case 'mapAO': - json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy ); - break; - case 'mapAORepeat': - case 'mapAOOffset': - case 'mapAOWrap': - case 'mapAOAnisotropy': - break; - case 'mapBump': - json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); - break; - case 'mapBumpScale': - json.bumpScale = value; - break; - case 'mapBumpRepeat': - case 'mapBumpOffset': - case 'mapBumpWrap': - case 'mapBumpAnisotropy': - break; - case 'mapNormal': - json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); - break; - case 'mapNormalFactor': - json.normalScale = value; - break; - case 'mapNormalRepeat': - case 'mapNormalOffset': - case 'mapNormalWrap': - case 'mapNormalAnisotropy': - break; - case 'mapSpecular': - json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); - break; - case 'mapSpecularRepeat': - case 'mapSpecularOffset': - case 'mapSpecularWrap': - case 'mapSpecularAnisotropy': - break; - case 'mapMetalness': - json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy ); - break; - case 'mapMetalnessRepeat': - case 'mapMetalnessOffset': - case 'mapMetalnessWrap': - case 'mapMetalnessAnisotropy': - break; - case 'mapRoughness': - json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy ); - break; - case 'mapRoughnessRepeat': - case 'mapRoughnessOffset': - case 'mapRoughnessWrap': - case 'mapRoughnessAnisotropy': - break; - case 'mapAlpha': - json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy ); - break; - case 'mapAlphaRepeat': - case 'mapAlphaOffset': - case 'mapAlphaWrap': - case 'mapAlphaAnisotropy': - break; - case 'flipSided': - json.side = BackSide; - break; - case 'doubleSided': - json.side = DoubleSide; - break; - case 'transparency': - console.warn( 'THREE.Loader.createMaterial: transparency has been renamed to opacity' ); - json.opacity = value; - break; - case 'depthTest': - case 'depthWrite': - case 'colorWrite': - case 'opacity': - case 'reflectivity': - case 'transparent': - case 'visible': - case 'wireframe': - json[ name ] = value; - break; - case 'vertexColors': - if ( value === true ) json.vertexColors = VertexColors; - if ( value === 'face' ) json.vertexColors = FaceColors; - break; - default: - console.error( 'THREE.Loader.createMaterial: Unsupported', name, value ); - break; + point.set( + px.calc( weight ), + py.calc( weight ), + pz.calc( weight ) + ); - } + return point; - } + }; - if ( json.type === 'MeshBasicMaterial' ) delete json.emissive; - if ( json.type !== 'MeshPhongMaterial' ) delete json.specular; + CatmullRomCurve3.prototype.copy = function ( source ) { - if ( json.opacity < 1 ) json.transparent = true; + Curve.prototype.copy.call( this, source ); - materialLoader.setTextures( textures ); + this.points = []; - return materialLoader.parse( json ); + for ( var i = 0, l = source.points.length; i < l; i ++ ) { - }; + var point = source.points[ i ]; - } )() + this.points.push( point.clone() ); - } ); + } - /** - * @author mrdoob / http://mrdoob.com/ - * @author alteredq / http://alteredqualia.com/ - */ + this.closed = source.closed; + this.curveType = source.curveType; + this.tension = source.tension; - function JSONLoader( manager ) { + return this; - if ( typeof manager === 'boolean' ) { + }; - console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' ); - manager = undefined; + CatmullRomCurve3.prototype.toJSON = function () { - } + var data = Curve.prototype.toJSON.call( this ); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + data.points = []; - this.withCredentials = false; + for ( var i = 0, l = this.points.length; i < l; i ++ ) { - } + var point = this.points[ i ]; + data.points.push( point.toArray() ); - Object.assign( JSONLoader.prototype, { + } - crossOrigin: 'anonymous', + data.closed = this.closed; + data.curveType = this.curveType; + data.tension = this.tension; - load: function ( url, onLoad, onProgress, onError ) { + return data; - var scope = this; + }; - var path = ( this.path === undefined ) ? LoaderUtils.extractUrlBase( url ) : this.path; + CatmullRomCurve3.prototype.fromJSON = function ( json ) { - var loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.setWithCredentials( this.withCredentials ); - loader.load( url, function ( text ) { + Curve.prototype.fromJSON.call( this, json ); - var json = JSON.parse( text ); - var metadata = json.metadata; + this.points = []; - if ( metadata !== undefined ) { + for ( var i = 0, l = json.points.length; i < l; i ++ ) { - var type = metadata.type; + var point = json.points[ i ]; + this.points.push( new Vector3().fromArray( point ) ); - if ( type !== undefined ) { + } - if ( type.toLowerCase() === 'object' ) { + this.closed = json.closed; + this.curveType = json.curveType; + this.tension = json.tension; - console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' ); - return; + return this; - } + }; - } + /** + * Bezier Curves formulas obtained from + * http://en.wikipedia.org/wiki/Bézier_curve + */ - } + function CatmullRom( t, p0, p1, p2, p3 ) { - var object = scope.parse( json, path ); - onLoad( object.geometry, object.materials ); + var v0 = ( p2 - p0 ) * 0.5; + var v1 = ( p3 - p1 ) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; - }, onProgress, onError ); + } - }, + // - setPath: function ( value ) { + function QuadraticBezierP0( t, p ) { - this.path = value; - return this; + var k = 1 - t; + return k * k * p; - }, + } - setResourcePath: function ( value ) { + function QuadraticBezierP1( t, p ) { - this.resourcePath = value; - return this; + return 2 * ( 1 - t ) * t * p; - }, + } - setCrossOrigin: function ( value ) { + function QuadraticBezierP2( t, p ) { - this.crossOrigin = value; - return this; + return t * t * p; - }, + } - parse: ( function () { + function QuadraticBezier( t, p0, p1, p2 ) { - function parseModel( json, geometry ) { + return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + + QuadraticBezierP2( t, p2 ); - function isBitSet( value, position ) { + } - return value & ( 1 << position ); + // - } + function CubicBezierP0( t, p ) { - var i, j, fi, + var k = 1 - t; + return k * k * k * p; - offset, zLength, + } - colorIndex, normalIndex, uvIndex, materialIndex, + function CubicBezierP1( t, p ) { - type, - isQuad, - hasMaterial, - hasFaceVertexUv, - hasFaceNormal, hasFaceVertexNormal, - hasFaceColor, hasFaceVertexColor, + var k = 1 - t; + return 3 * k * k * t * p; - vertex, face, faceA, faceB, hex, normal, + } - uvLayer, uv, u, v, + function CubicBezierP2( t, p ) { - faces = json.faces, - vertices = json.vertices, - normals = json.normals, - colors = json.colors, + return 3 * ( 1 - t ) * t * t * p; - scale = json.scale, + } - nUvLayers = 0; + function CubicBezierP3( t, p ) { + return t * t * t * p; - if ( json.uvs !== undefined ) { + } - // disregard empty arrays + function CubicBezier( t, p0, p1, p2, p3 ) { - for ( i = 0; i < json.uvs.length; i ++ ) { + return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + + CubicBezierP3( t, p3 ); - if ( json.uvs[ i ].length ) nUvLayers ++; + } - } + function CubicBezierCurve( v0, v1, v2, v3 ) { - for ( i = 0; i < nUvLayers; i ++ ) { + Curve.call( this ); - geometry.faceVertexUvs[ i ] = []; + this.type = 'CubicBezierCurve'; - } + this.v0 = v0 || new Vector2(); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); + this.v3 = v3 || new Vector2(); - } + } - offset = 0; - zLength = vertices.length; + CubicBezierCurve.prototype = Object.create( Curve.prototype ); + CubicBezierCurve.prototype.constructor = CubicBezierCurve; - while ( offset < zLength ) { + CubicBezierCurve.prototype.isCubicBezierCurve = true; - vertex = new Vector3(); + CubicBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { - vertex.x = vertices[ offset ++ ] * scale; - vertex.y = vertices[ offset ++ ] * scale; - vertex.z = vertices[ offset ++ ] * scale; + var point = optionalTarget || new Vector2(); - geometry.vertices.push( vertex ); + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - } + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) + ); - offset = 0; - zLength = faces.length; + return point; - while ( offset < zLength ) { + }; - type = faces[ offset ++ ]; + CubicBezierCurve.prototype.copy = function ( source ) { - isQuad = isBitSet( type, 0 ); - hasMaterial = isBitSet( type, 1 ); - hasFaceVertexUv = isBitSet( type, 3 ); - hasFaceNormal = isBitSet( type, 4 ); - hasFaceVertexNormal = isBitSet( type, 5 ); - hasFaceColor = isBitSet( type, 6 ); - hasFaceVertexColor = isBitSet( type, 7 ); + Curve.prototype.copy.call( this, source ); - // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - if ( isQuad ) { + return this; - faceA = new Face3(); - faceA.a = faces[ offset ]; - faceA.b = faces[ offset + 1 ]; - faceA.c = faces[ offset + 3 ]; + }; - faceB = new Face3(); - faceB.a = faces[ offset + 1 ]; - faceB.b = faces[ offset + 2 ]; - faceB.c = faces[ offset + 3 ]; + CubicBezierCurve.prototype.toJSON = function () { - offset += 4; + var data = Curve.prototype.toJSON.call( this ); - if ( hasMaterial ) { + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - materialIndex = faces[ offset ++ ]; - faceA.materialIndex = materialIndex; - faceB.materialIndex = materialIndex; + return data; - } + }; - // to get face <=> uv index correspondence + CubicBezierCurve.prototype.fromJSON = function ( json ) { - fi = geometry.faces.length; + Curve.prototype.fromJSON.call( this, json ); - if ( hasFaceVertexUv ) { + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); - for ( i = 0; i < nUvLayers; i ++ ) { + return this; - uvLayer = json.uvs[ i ]; + }; - geometry.faceVertexUvs[ i ][ fi ] = []; - geometry.faceVertexUvs[ i ][ fi + 1 ] = []; + function CubicBezierCurve3( v0, v1, v2, v3 ) { - for ( j = 0; j < 4; j ++ ) { + Curve.call( this ); - uvIndex = faces[ offset ++ ]; + this.type = 'CubicBezierCurve3'; - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + this.v0 = v0 || new Vector3(); + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); + this.v3 = v3 || new Vector3(); - uv = new Vector2( u, v ); + } - if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); - if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); + CubicBezierCurve3.prototype = Object.create( Curve.prototype ); + CubicBezierCurve3.prototype.constructor = CubicBezierCurve3; - } + CubicBezierCurve3.prototype.isCubicBezierCurve3 = true; - } + CubicBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector3(); - if ( hasFaceNormal ) { + var v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; - normalIndex = faces[ offset ++ ] * 3; + point.set( + CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), + CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), + CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) + ); - faceA.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + return point; - faceB.normal.copy( faceA.normal ); + }; - } + CubicBezierCurve3.prototype.copy = function ( source ) { - if ( hasFaceVertexNormal ) { + Curve.prototype.copy.call( this, source ); - for ( i = 0; i < 4; i ++ ) { + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); + this.v3.copy( source.v3 ); - normalIndex = faces[ offset ++ ] * 3; + return this; - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + }; + CubicBezierCurve3.prototype.toJSON = function () { - if ( i !== 2 ) faceA.vertexNormals.push( normal ); - if ( i !== 0 ) faceB.vertexNormals.push( normal ); + var data = Curve.prototype.toJSON.call( this ); - } + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); + data.v3 = this.v3.toArray(); - } + return data; + }; - if ( hasFaceColor ) { + CubicBezierCurve3.prototype.fromJSON = function ( json ) { - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + Curve.prototype.fromJSON.call( this, json ); - faceA.color.setHex( hex ); - faceB.color.setHex( hex ); + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); + this.v3.fromArray( json.v3 ); - } + return this; + }; - if ( hasFaceVertexColor ) { + function LineCurve( v1, v2 ) { - for ( i = 0; i < 4; i ++ ) { + Curve.call( this ); - colorIndex = faces[ offset ++ ]; - hex = colors[ colorIndex ]; + this.type = 'LineCurve'; - if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) ); - if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) ); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); - } + } - } + LineCurve.prototype = Object.create( Curve.prototype ); + LineCurve.prototype.constructor = LineCurve; - geometry.faces.push( faceA ); - geometry.faces.push( faceB ); + LineCurve.prototype.isLineCurve = true; - } else { + LineCurve.prototype.getPoint = function ( t, optionalTarget ) { - face = new Face3(); - face.a = faces[ offset ++ ]; - face.b = faces[ offset ++ ]; - face.c = faces[ offset ++ ]; + var point = optionalTarget || new Vector2(); - if ( hasMaterial ) { + if ( t === 1 ) { - materialIndex = faces[ offset ++ ]; - face.materialIndex = materialIndex; + point.copy( this.v2 ); - } + } else { - // to get face <=> uv index correspondence + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); - fi = geometry.faces.length; + } - if ( hasFaceVertexUv ) { + return point; - for ( i = 0; i < nUvLayers; i ++ ) { + }; - uvLayer = json.uvs[ i ]; + // Line curve is linear, so we can overwrite default getPointAt - geometry.faceVertexUvs[ i ][ fi ] = []; + LineCurve.prototype.getPointAt = function ( u, optionalTarget ) { - for ( j = 0; j < 3; j ++ ) { + return this.getPoint( u, optionalTarget ); - uvIndex = faces[ offset ++ ]; + }; - u = uvLayer[ uvIndex * 2 ]; - v = uvLayer[ uvIndex * 2 + 1 ]; + LineCurve.prototype.getTangent = function ( t, optionalTarget ) { - uv = new Vector2( u, v ); + var tangent = optionalTarget || new Vector2(); - geometry.faceVertexUvs[ i ][ fi ].push( uv ); + tangent.copy( this.v2 ).sub( this.v1 ).normalize(); - } + return tangent; - } + }; - } + LineCurve.prototype.copy = function ( source ) { - if ( hasFaceNormal ) { + Curve.prototype.copy.call( this, source ); - normalIndex = faces[ offset ++ ] * 3; + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - face.normal.set( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + return this; - } + }; - if ( hasFaceVertexNormal ) { + LineCurve.prototype.toJSON = function () { - for ( i = 0; i < 3; i ++ ) { + var data = Curve.prototype.toJSON.call( this ); - normalIndex = faces[ offset ++ ] * 3; + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - normal = new Vector3( - normals[ normalIndex ++ ], - normals[ normalIndex ++ ], - normals[ normalIndex ] - ); + return data; - face.vertexNormals.push( normal ); + }; - } + LineCurve.prototype.fromJSON = function ( json ) { - } + Curve.prototype.fromJSON.call( this, json ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - if ( hasFaceColor ) { + return this; - colorIndex = faces[ offset ++ ]; - face.color.setHex( colors[ colorIndex ] ); + }; - } + function LineCurve3( v1, v2 ) { + Curve.call( this ); - if ( hasFaceVertexColor ) { + this.type = 'LineCurve3'; - for ( i = 0; i < 3; i ++ ) { + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); - colorIndex = faces[ offset ++ ]; - face.vertexColors.push( new Color( colors[ colorIndex ] ) ); + } - } + LineCurve3.prototype = Object.create( Curve.prototype ); + LineCurve3.prototype.constructor = LineCurve3; - } + LineCurve3.prototype.isLineCurve3 = true; - geometry.faces.push( face ); + LineCurve3.prototype.getPoint = function ( t, optionalTarget ) { - } + var point = optionalTarget || new Vector3(); - } + if ( t === 1 ) { - } + point.copy( this.v2 ); - function parseSkin( json, geometry ) { + } else { - var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2; + point.copy( this.v2 ).sub( this.v1 ); + point.multiplyScalar( t ).add( this.v1 ); - if ( json.skinWeights ) { + } - for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) { + return point; - var x = json.skinWeights[ i ]; - var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0; - var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0; - var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0; + }; - geometry.skinWeights.push( new Vector4( x, y, z, w ) ); + // Line curve is linear, so we can overwrite default getPointAt - } + LineCurve3.prototype.getPointAt = function ( u, optionalTarget ) { - } + return this.getPoint( u, optionalTarget ); - if ( json.skinIndices ) { + }; - for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) { + LineCurve3.prototype.copy = function ( source ) { - var a = json.skinIndices[ i ]; - var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0; - var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0; - var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0; + Curve.prototype.copy.call( this, source ); - geometry.skinIndices.push( new Vector4( a, b, c, d ) ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - } + return this; - } + }; - geometry.bones = json.bones; + LineCurve3.prototype.toJSON = function () { - if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { + var data = Curve.prototype.toJSON.call( this ); - console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + - geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - } + return data; - } + }; - function parseMorphing( json, geometry ) { + LineCurve3.prototype.fromJSON = function ( json ) { - var scale = json.scale; + Curve.prototype.fromJSON.call( this, json ); - if ( json.morphTargets !== undefined ) { + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) { + return this; - geometry.morphTargets[ i ] = {}; - geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; - geometry.morphTargets[ i ].vertices = []; + }; - var dstVertices = geometry.morphTargets[ i ].vertices; - var srcVertices = json.morphTargets[ i ].vertices; + function QuadraticBezierCurve( v0, v1, v2 ) { - for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) { + Curve.call( this ); - var vertex = new Vector3(); - vertex.x = srcVertices[ v ] * scale; - vertex.y = srcVertices[ v + 1 ] * scale; - vertex.z = srcVertices[ v + 2 ] * scale; + this.type = 'QuadraticBezierCurve'; - dstVertices.push( vertex ); + this.v0 = v0 || new Vector2(); + this.v1 = v1 || new Vector2(); + this.v2 = v2 || new Vector2(); - } + } - } + QuadraticBezierCurve.prototype = Object.create( Curve.prototype ); + QuadraticBezierCurve.prototype.constructor = QuadraticBezierCurve; - } + QuadraticBezierCurve.prototype.isQuadraticBezierCurve = true; - if ( json.morphColors !== undefined && json.morphColors.length > 0 ) { + QuadraticBezierCurve.prototype.getPoint = function ( t, optionalTarget ) { - console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' ); + var point = optionalTarget || new Vector2(); - var faces = geometry.faces; - var morphColors = json.morphColors[ 0 ].colors; + var v0 = this.v0, v1 = this.v1, v2 = this.v2; - for ( var i = 0, l = faces.length; i < l; i ++ ) { + point.set( + QuadraticBezier( t, v0.x, v1.x, v2.x ), + QuadraticBezier( t, v0.y, v1.y, v2.y ) + ); - faces[ i ].color.fromArray( morphColors, i * 3 ); + return point; - } + }; - } + QuadraticBezierCurve.prototype.copy = function ( source ) { - } + Curve.prototype.copy.call( this, source ); - function parseAnimations( json, geometry ) { + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - var outputAnimations = []; + return this; - // parse old style Bone/Hierarchy animations - var animations = []; + }; - if ( json.animation !== undefined ) { + QuadraticBezierCurve.prototype.toJSON = function () { - animations.push( json.animation ); + var data = Curve.prototype.toJSON.call( this ); - } + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - if ( json.animations !== undefined ) { + return data; - if ( json.animations.length ) { + }; - animations = animations.concat( json.animations ); + QuadraticBezierCurve.prototype.fromJSON = function ( json ) { - } else { + Curve.prototype.fromJSON.call( this, json ); - animations.push( json.animations ); + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - } + return this; - } + }; - for ( var i = 0; i < animations.length; i ++ ) { + function QuadraticBezierCurve3( v0, v1, v2 ) { - var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones ); - if ( clip ) outputAnimations.push( clip ); + Curve.call( this ); - } + this.type = 'QuadraticBezierCurve3'; - // parse implicit morph animations - if ( geometry.morphTargets ) { + this.v0 = v0 || new Vector3(); + this.v1 = v1 || new Vector3(); + this.v2 = v2 || new Vector3(); - // TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary. - var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 ); - outputAnimations = outputAnimations.concat( morphAnimationClips ); + } - } + QuadraticBezierCurve3.prototype = Object.create( Curve.prototype ); + QuadraticBezierCurve3.prototype.constructor = QuadraticBezierCurve3; - if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations; + QuadraticBezierCurve3.prototype.isQuadraticBezierCurve3 = true; - } + QuadraticBezierCurve3.prototype.getPoint = function ( t, optionalTarget ) { - return function parse( json, path ) { + var point = optionalTarget || new Vector3(); - if ( json.data !== undefined ) { + var v0 = this.v0, v1 = this.v1, v2 = this.v2; - // Geometry 4.0 spec - json = json.data; + 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; - if ( json.scale !== undefined ) { + }; - json.scale = 1.0 / json.scale; + QuadraticBezierCurve3.prototype.copy = function ( source ) { - } else { + Curve.prototype.copy.call( this, source ); - json.scale = 1.0; + this.v0.copy( source.v0 ); + this.v1.copy( source.v1 ); + this.v2.copy( source.v2 ); - } + return this; - var geometry = new Geometry(); + }; - parseModel( json, geometry ); - parseSkin( json, geometry ); - parseMorphing( json, geometry ); - parseAnimations( json, geometry ); + QuadraticBezierCurve3.prototype.toJSON = function () { - geometry.computeFaceNormals(); - geometry.computeBoundingSphere(); + var data = Curve.prototype.toJSON.call( this ); - if ( json.materials === undefined || json.materials.length === 0 ) { + data.v0 = this.v0.toArray(); + data.v1 = this.v1.toArray(); + data.v2 = this.v2.toArray(); - return { geometry: geometry }; + return data; - } else { + }; - var materials = Loader.prototype.initMaterials( json.materials, this.resourcePath || path, this.crossOrigin ); + QuadraticBezierCurve3.prototype.fromJSON = function ( json ) { - return { geometry: geometry, materials: materials }; + Curve.prototype.fromJSON.call( this, json ); - } + this.v0.fromArray( json.v0 ); + this.v1.fromArray( json.v1 ); + this.v2.fromArray( json.v2 ); - }; + return this; - } )() + }; - } ); + function SplineCurve( points ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + Curve.call( this ); - function ObjectLoader( manager ) { + this.type = 'SplineCurve'; - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; - this.resourcePath = ''; + this.points = points || []; } - Object.assign( ObjectLoader.prototype, { - - crossOrigin: 'anonymous', + SplineCurve.prototype = Object.create( Curve.prototype ); + SplineCurve.prototype.constructor = SplineCurve; - load: function ( url, onLoad, onProgress, onError ) { + SplineCurve.prototype.isSplineCurve = true; - var scope = this; + SplineCurve.prototype.getPoint = function ( t, optionalTarget ) { - var path = ( this.path === undefined ) ? LoaderUtils.extractUrlBase( url ) : this.path; - this.resourcePath = this.resourcePath || path; + var point = optionalTarget || new Vector2(); - var loader = new FileLoader( scope.manager ); - loader.setPath( this.path ); - loader.load( url, function ( text ) { + var points = this.points; + var p = ( points.length - 1 ) * t; - var json = null; + var intPoint = Math.floor( p ); + var weight = p - intPoint; - try { + var p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; + var p1 = points[ intPoint ]; + var p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; + var p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; - json = JSON.parse( text ); + point.set( + CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), + CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) + ); - } catch ( error ) { + return point; - if ( onError !== undefined ) onError( error ); + }; - console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); + SplineCurve.prototype.copy = function ( source ) { - return; + Curve.prototype.copy.call( this, source ); - } + this.points = []; - var metadata = json.metadata; + for ( var i = 0, l = source.points.length; i < l; i ++ ) { - if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { + var point = source.points[ i ]; - console.error( 'THREE.ObjectLoader: Can\'t load ' + url + '. Use THREE.JSONLoader instead.' ); - return; + this.points.push( point.clone() ); - } + } - scope.parse( json, onLoad ); + return this; - }, onProgress, onError ); + }; - }, + SplineCurve.prototype.toJSON = function () { - setPath: function ( value ) { + var data = Curve.prototype.toJSON.call( this ); - this.path = value; - return this; + data.points = []; - }, + for ( var i = 0, l = this.points.length; i < l; i ++ ) { - setResourcePath: function ( value ) { + var point = this.points[ i ]; + data.points.push( point.toArray() ); - this.resourcePath = value; - return this; + } - }, + return data; - setCrossOrigin: function ( value ) { + }; - this.crossOrigin = value; - return this; + SplineCurve.prototype.fromJSON = function ( json ) { - }, + Curve.prototype.fromJSON.call( this, json ); - parse: function ( json, onLoad ) { + this.points = []; - var shapes = this.parseShape( json.shapes ); - var geometries = this.parseGeometries( json.geometries, shapes ); + for ( var i = 0, l = json.points.length; i < l; i ++ ) { - var images = this.parseImages( json.images, function () { + var point = json.points[ i ]; + this.points.push( new Vector2().fromArray( point ) ); - if ( onLoad !== undefined ) onLoad( object ); + } - } ); + return this; - var textures = this.parseTextures( json.textures, images ); - var materials = this.parseMaterials( json.materials, textures ); + }; - var object = this.parseObject( json.object, geometries, materials ); + 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 + }); - if ( json.animations ) { + /************************************************************** + * Curved Path - a curve path is simply a array of connected + * curves, but retains the api of a curve + **************************************************************/ - object.animations = this.parseAnimations( json.animations ); + function CurvePath() { - } + Curve.call( this ); - if ( json.images === undefined || json.images.length === 0 ) { + this.type = 'CurvePath'; - if ( onLoad !== undefined ) onLoad( object ); + this.curves = []; + this.autoClose = false; // Automatically closes the path - } + } - return object; + CurvePath.prototype = Object.assign( Object.create( Curve.prototype ), { - }, + constructor: CurvePath, - parseShape: function ( json ) { + add: function ( curve ) { - var shapes = {}; + this.curves.push( curve ); - if ( json !== undefined ) { + }, - for ( var i = 0, l = json.length; i < l; i ++ ) { + closePath: function () { - var shape = new Shape().fromJSON( json[ i ] ); + // Add a line curve if start and end of lines are not connected + var startPoint = this.curves[ 0 ].getPoint( 0 ); + var endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); - shapes[ shape.uuid ] = shape; + if ( ! startPoint.equals( endPoint ) ) { - } + this.curves.push( new LineCurve( endPoint, startPoint ) ); } - return shapes; - }, - parseGeometries: function ( json, shapes ) { + // To get accurate point with reference to + // entire path distance at time t, + // following has to be done: - var geometries = {}; + // 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') - if ( json !== undefined ) { + getPoint: function ( t ) { - var geometryLoader = new JSONLoader(); - var bufferGeometryLoader = new BufferGeometryLoader(); + var d = t * this.getLength(); + var curveLengths = this.getCurveLengths(); + var i = 0; - for ( var i = 0, l = json.length; i < l; i ++ ) { + // To think about boundaries points. - var geometry; - var data = json[ i ]; + while ( i < curveLengths.length ) { - switch ( data.type ) { + if ( curveLengths[ i ] >= d ) { - case 'PlaneGeometry': - case 'PlaneBufferGeometry': + var diff = curveLengths[ i ] - d; + var curve = this.curves[ i ]; - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.widthSegments, - data.heightSegments - ); + var segmentLength = curve.getLength(); + var u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; - break; + return curve.getPointAt( u ); - case 'BoxGeometry': - case 'BoxBufferGeometry': - case 'CubeGeometry': // backwards compatible + } - geometry = new Geometries[ data.type ]( - data.width, - data.height, - data.depth, - data.widthSegments, - data.heightSegments, - data.depthSegments - ); + i ++; - break; + } - case 'CircleGeometry': - case 'CircleBufferGeometry': + return null; - geometry = new Geometries[ data.type ]( - data.radius, - data.segments, - data.thetaStart, - data.thetaLength - ); + // loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { - } + points.push( points[ 0 ] ); - geometry = new Geometries[ data.type ]( - geometryShapes, - data.options - ); + } - break; + return points; - case 'BufferGeometry': + }, - geometry = bufferGeometryLoader.parse( data ); + copy: function ( source ) { - break; + Curve.prototype.copy.call( this, source ); - case 'Geometry': + this.curves = []; - geometry = geometryLoader.parse( data, this.resourcePath ).geometry; + for ( var i = 0, l = source.curves.length; i < l; i ++ ) { - break; + var curve = source.curves[ i ]; - default: + this.curves.push( curve.clone() ); - console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); + } - continue; + this.autoClose = source.autoClose; - } + return this; - geometry.uuid = data.uuid; + }, - if ( data.name !== undefined ) geometry.name = data.name; - if ( geometry.isBufferGeometry === true && data.userData !== undefined ) geometry.userData = data.userData; + toJSON: function () { - geometries[ data.uuid ] = geometry; + var data = Curve.prototype.toJSON.call( this ); - } + data.autoClose = this.autoClose; + data.curves = []; + + for ( var i = 0, l = this.curves.length; i < l; i ++ ) { + + var curve = this.curves[ i ]; + data.curves.push( curve.toJSON() ); } - return geometries; + return data; }, - parseMaterials: function ( json, textures ) { + fromJSON: function ( json ) { - var cache = {}; // MultiMaterial - var materials = {}; + Curve.prototype.fromJSON.call( this, json ); - if ( json !== undefined ) { + this.autoClose = json.autoClose; + this.curves = []; - var loader = new MaterialLoader(); - loader.setTextures( textures ); + for ( var i = 0, l = json.curves.length; i < l; i ++ ) { - for ( var i = 0, l = json.length; i < l; i ++ ) { + var curve = json.curves[ i ]; + this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); - var data = json[ i ]; + } - if ( data.type === 'MultiMaterial' ) { + return this; - // Deprecated + } - var array = []; + } ); - for ( var j = 0; j < data.materials.length; j ++ ) { + function Path( points ) { - var material = data.materials[ j ]; + CurvePath.call( this ); - if ( cache[ material.uuid ] === undefined ) { + this.type = 'Path'; - cache[ material.uuid ] = loader.parse( material ); + this.currentPoint = new Vector2(); - } + if ( points ) { - array.push( cache[ material.uuid ] ); + this.setFromPoints( points ); - } + } - materials[ data.uuid ] = array; + } - } else { + Path.prototype = Object.assign( Object.create( CurvePath.prototype ), { - materials[ data.uuid ] = loader.parse( data ); - cache[ data.uuid ] = materials[ data.uuid ]; + constructor: Path, - } + setFromPoints: function ( points ) { - } + this.moveTo( points[ 0 ].x, points[ 0 ].y ); + + for ( var i = 1, l = points.length; i < l; i ++ ) { + + this.lineTo( points[ i ].x, points[ i ].y ); } - return materials; + return this; }, - parseAnimations: function ( json ) { - - var animations = []; + moveTo: function ( x, y ) { - for ( var i = 0; i < json.length; i ++ ) { + this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? - var data = json[ i ]; + return this; - var clip = AnimationClip.parse( data ); + }, - if ( data.uuid !== undefined ) clip.uuid = data.uuid; + lineTo: function ( x, y ) { - animations.push( clip ); + var curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); + this.curves.push( curve ); - } + this.currentPoint.set( x, y ); - return animations; + return this; }, - parseImages: function ( json, onLoad ) { + quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { - var scope = this; - var images = {}; + var curve = new QuadraticBezierCurve( + this.currentPoint.clone(), + new Vector2( aCPx, aCPy ), + new Vector2( aX, aY ) + ); - function loadImage( url ) { + this.curves.push( curve ); - scope.manager.itemStart( url ); + this.currentPoint.set( aX, aY ); - return loader.load( url, function () { + return this; - scope.manager.itemEnd( url ); + }, - }, undefined, function () { + bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + var 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 ); - if ( json !== undefined && json.length > 0 ) { + return this; - var manager = new LoadingManager( onLoad ); + }, - var loader = new ImageLoader( manager ); - loader.setCrossOrigin( this.crossOrigin ); + splineThru: function ( pts /*Array of Vector*/ ) { - for ( var i = 0, il = json.length; i < il; i ++ ) { + var npts = [ this.currentPoint.clone() ].concat( pts ); - var image = json[ i ]; - var url = image.url; + var curve = new SplineCurve( npts ); + this.curves.push( curve ); - if ( Array.isArray( url ) ) { + this.currentPoint.copy( pts[ pts.length - 1 ] ); - // load array of images e.g CubeTexture + return this; - images[ image.uuid ] = []; + }, - for ( var j = 0, jl = url.length; j < jl; j ++ ) { + arc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - var currentUrl = url[ j ]; + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; - var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( currentUrl ) ? currentUrl : scope.resourcePath + currentUrl; + this.absarc( aX + x0, aY + y0, aRadius, + aStartAngle, aEndAngle, aClockwise ); - images[ image.uuid ].push( loadImage( path ) ); + return this; - } + }, - } else { + absarc: function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { - // load single image + this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); - var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.resourcePath + image.url; + return this; - images[ image.uuid ] = loadImage( path ); + }, - } + ellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - } + var x0 = this.currentPoint.x; + var y0 = this.currentPoint.y; - } + this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - return images; + return this; }, - parseTextures: function ( json, images ) { + absellipse: function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { - function parseConstant( value, type ) { + var curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); - if ( typeof value === 'number' ) return value; + if ( this.curves.length > 0 ) { - console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); + // if a previous curve is present, attempt to join + var firstPoint = curve.getPoint( 0 ); - return type[ value ]; + if ( ! firstPoint.equals( this.currentPoint ) ) { - } + this.lineTo( firstPoint.x, firstPoint.y ); - var textures = {}; + } - if ( json !== undefined ) { + } - for ( var i = 0, l = json.length; i < l; i ++ ) { + this.curves.push( curve ); - var data = json[ i ]; + var lastPoint = curve.getPoint( 1 ); + this.currentPoint.copy( lastPoint ); - if ( data.image === undefined ) { + return this; - console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); + }, - } + copy: function ( source ) { - if ( images[ data.image ] === undefined ) { + CurvePath.prototype.copy.call( this, source ); - console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); + this.currentPoint.copy( source.currentPoint ); - } + return this; - var texture; + }, - if ( Array.isArray( images[ data.image ] ) ) { + toJSON: function () { - texture = new CubeTexture( images[ data.image ] ); + var data = CurvePath.prototype.toJSON.call( this ); - } else { + data.currentPoint = this.currentPoint.toArray(); - texture = new Texture( images[ data.image ] ); + return data; - } + }, - texture.needsUpdate = true; + fromJSON: function ( json ) { - texture.uuid = data.uuid; + CurvePath.prototype.fromJSON.call( this, json ); - if ( data.name !== undefined ) texture.name = data.name; + this.currentPoint.fromArray( json.currentPoint ); - if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); + return this; - 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 ); + function Shape( points ) { - } + Path.call( this, points ); - if ( data.format !== undefined ) texture.format = data.format; + this.uuid = MathUtils.generateUUID(); - 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; + this.type = 'Shape'; - if ( data.flipY !== undefined ) texture.flipY = data.flipY; + this.holes = []; - textures[ data.uuid ] = texture; + } - } + Shape.prototype = Object.assign( Object.create( Path.prototype ), { - } + constructor: Shape, - return textures; + getPointsHoles: function ( divisions ) { - }, + var holesPts = []; - parseObject: function ( data, geometries, materials ) { + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { - var object; + holesPts[ i ] = this.holes[ i ].getPoints( divisions ); - function getGeometry( name ) { + } - if ( geometries[ name ] === undefined ) { + return holesPts; - console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); + }, - } + // get points of shape and holes (keypoints based on segments parameter) - return geometries[ name ]; + extractPoints: function ( divisions ) { - } + return { - function getMaterial( name ) { + shape: this.getPoints( divisions ), + holes: this.getPointsHoles( divisions ) - if ( name === undefined ) return undefined; + }; - if ( Array.isArray( name ) ) { + }, - var array = []; + copy: function ( source ) { - for ( var i = 0, l = name.length; i < l; i ++ ) { + Path.prototype.copy.call( this, source ); - var uuid = name[ i ]; + this.holes = []; - if ( materials[ uuid ] === undefined ) { + for ( var i = 0, l = source.holes.length; i < l; i ++ ) { - console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + var hole = source.holes[ i ]; - } + this.holes.push( hole.clone() ); - array.push( materials[ uuid ] ); + } - } + return this; - return array; + }, - } + toJSON: function () { - if ( materials[ name ] === undefined ) { + var data = Path.prototype.toJSON.call( this ); - console.warn( 'THREE.ObjectLoader: Undefined material', name ); + data.uuid = this.uuid; + data.holes = []; - } + for ( var i = 0, l = this.holes.length; i < l; i ++ ) { - return materials[ name ]; + var hole = this.holes[ i ]; + data.holes.push( hole.toJSON() ); } - switch ( data.type ) { + return data; - case 'Scene': + }, - object = new Scene(); + fromJSON: function ( json ) { - if ( data.background !== undefined ) { + Path.prototype.fromJSON.call( this, json ); - if ( Number.isInteger( data.background ) ) { + this.uuid = json.uuid; + this.holes = []; - object.background = new Color( data.background ); + for ( var i = 0, l = json.holes.length; i < l; i ++ ) { - } + var hole = json.holes[ i ]; + this.holes.push( new Path().fromJSON( hole ) ); - } + } - if ( data.fog !== undefined ) { + return this; - if ( data.fog.type === 'Fog' ) { + } - object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); + } ); - } else if ( data.fog.type === 'FogExp2' ) { + function Light( color, intensity ) { - object.fog = new FogExp2( data.fog.color, data.fog.density ); + Object3D.call( this ); - } + this.type = 'Light'; - } + this.color = new Color( color ); + this.intensity = intensity !== undefined ? intensity : 1; - break; + this.receiveShadow = undefined; - case 'PerspectiveCamera': + } - object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); + Light.prototype = Object.assign( Object.create( Object3D.prototype ), { - 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 ); + constructor: Light, - break; + isLight: true, - case 'OrthographicCamera': + copy: function ( source ) { - object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); + Object3D.prototype.copy.call( this, source ); - if ( data.zoom !== undefined ) object.zoom = data.zoom; - if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); + this.color.copy( source.color ); + this.intensity = source.intensity; - break; + return this; - case 'AmbientLight': + }, - object = new AmbientLight( data.color, data.intensity ); + toJSON: function ( meta ) { - break; + var data = Object3D.prototype.toJSON.call( this, meta ); - case 'DirectionalLight': + data.object.color = this.color.getHex(); + data.object.intensity = this.intensity; - object = new DirectionalLight( data.color, data.intensity ); + if ( this.groundColor !== undefined ) { data.object.groundColor = this.groundColor.getHex(); } - break; + 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; } - case 'PointLight': + if ( this.shadow !== undefined ) { data.object.shadow = this.shadow.toJSON(); } - object = new PointLight( data.color, data.intensity, data.distance, data.decay ); + return data; - break; + } - case 'RectAreaLight': + } ); - object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); + function HemisphereLight( skyColor, groundColor, intensity ) { - break; + Light.call( this, skyColor, intensity ); - case 'SpotLight': + this.type = 'HemisphereLight'; - object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); + this.castShadow = undefined; - break; + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - case 'HemisphereLight': + this.groundColor = new Color( groundColor ); - object = new HemisphereLight( data.color, data.groundColor, data.intensity ); + } - break; + HemisphereLight.prototype = Object.assign( Object.create( Light.prototype ), { - case 'SkinnedMesh': + constructor: HemisphereLight, - console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); + isHemisphereLight: true, - case 'Mesh': + copy: function ( source ) { - var geometry = getGeometry( data.geometry ); - var material = getMaterial( data.material ); + Light.prototype.copy.call( this, source ); - if ( geometry.bones && geometry.bones.length > 0 ) { + this.groundColor.copy( source.groundColor ); - object = new SkinnedMesh( geometry, material ); + return this; - } else { + } - object = new Mesh( geometry, material ); + } ); - } + function LightShadow( camera ) { - break; + this.camera = camera; - case 'LOD': + this.bias = 0; + this.normalBias = 0; + this.radius = 1; - object = new LOD(); + this.mapSize = new Vector2( 512, 512 ); - break; + this.map = null; + this.mapPass = null; + this.matrix = new Matrix4(); - case 'Line': + this.autoUpdate = true; + this.needsUpdate = false; - object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); + this._frustum = new Frustum(); + this._frameExtents = new Vector2( 1, 1 ); - break; + this._viewportCount = 1; - case 'LineLoop': + this._viewports = [ - object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); + new Vector4( 0, 0, 1, 1 ) - break; + ]; - case 'LineSegments': + } - object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); + Object.assign( LightShadow.prototype, { - break; + _projScreenMatrix: new Matrix4(), - case 'PointCloud': - case 'Points': + _lightPositionWorld: new Vector3(), - object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); + _lookTarget: new Vector3(), - break; + getViewportCount: function () { - case 'Sprite': + return this._viewportCount; - object = new Sprite( getMaterial( data.material ) ); + }, - break; + getFrustum: function () { - case 'Group': + return this._frustum; - object = new Group(); + }, - break; + updateMatrices: function ( light ) { - default: + var shadowCamera = this.camera, + shadowMatrix = this.matrix, + projScreenMatrix = this._projScreenMatrix, + lookTarget = this._lookTarget, + lightPositionWorld = this._lightPositionWorld; - object = new Object3D(); + lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); + shadowCamera.position.copy( lightPositionWorld ); - } + lookTarget.setFromMatrixPosition( light.target.matrixWorld ); + shadowCamera.lookAt( lookTarget ); + shadowCamera.updateMatrixWorld(); - object.uuid = data.uuid; + projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); + this._frustum.setFromProjectionMatrix( projScreenMatrix ); - if ( data.name !== undefined ) object.name = data.name; + 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 + ); - if ( data.matrix !== undefined ) { + shadowMatrix.multiply( shadowCamera.projectionMatrix ); + shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); - 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 ); + getViewport: function ( viewportIndex ) { - } else { + return this._viewports[ viewportIndex ]; - 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 ); + }, - } + getFrameExtents: function () { - if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; - if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; + return this._frameExtents; - if ( data.shadow ) { + }, - if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; - if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; - if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); - if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); + copy: function ( source ) { - } + this.camera = source.camera.clone(); - 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; + this.bias = source.bias; + this.radius = source.radius; - if ( data.children !== undefined ) { + this.mapSize.copy( source.mapSize ); - var children = data.children; + return this; - for ( var i = 0; i < children.length; i ++ ) { + }, - object.add( this.parseObject( children[ i ], geometries, materials ) ); + clone: function () { - } + return new this.constructor().copy( this ); - } + }, - if ( data.type === 'LOD' ) { + toJSON: function () { - var levels = data.levels; + var object = {}; - for ( var l = 0; l < levels.length; l ++ ) { + 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(); } - var level = levels[ l ]; - var child = object.getObjectByProperty( 'uuid', level.object ); + object.camera = this.camera.toJSON( false ).object; + delete object.camera.matrix; - if ( child !== undefined ) { + return object; - object.addLevel( child, level.distance ); + } - } + } ); - } + function SpotLightShadow() { - } + LightShadow.call( this, new PerspectiveCamera( 50, 1, 0.5, 500 ) ); - return object; + } - } + SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - } ); + constructor: SpotLightShadow, - var TEXTURE_MAPPING = { - UVMapping: UVMapping, - CubeReflectionMapping: CubeReflectionMapping, - CubeRefractionMapping: CubeRefractionMapping, - EquirectangularReflectionMapping: EquirectangularReflectionMapping, - EquirectangularRefractionMapping: EquirectangularRefractionMapping, - SphericalReflectionMapping: SphericalReflectionMapping, - CubeUVReflectionMapping: CubeUVReflectionMapping, - CubeUVRefractionMapping: CubeUVRefractionMapping - }; + isSpotLightShadow: true, - var TEXTURE_WRAPPING = { - RepeatWrapping: RepeatWrapping, - ClampToEdgeWrapping: ClampToEdgeWrapping, - MirroredRepeatWrapping: MirroredRepeatWrapping - }; + updateMatrices: function ( light ) { - var TEXTURE_FILTER = { - NearestFilter: NearestFilter, - NearestMipMapNearestFilter: NearestMipMapNearestFilter, - NearestMipMapLinearFilter: NearestMipMapLinearFilter, - LinearFilter: LinearFilter, - LinearMipMapNearestFilter: LinearMipMapNearestFilter, - LinearMipMapLinearFilter: LinearMipMapLinearFilter - }; + var camera = this.camera; - /** - * @author thespite / http://clicktorelease.com/ - */ + var fov = MathUtils.RAD2DEG * 2 * light.angle; + var aspect = this.mapSize.width / this.mapSize.height; + var far = light.distance || camera.far; + if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { - function ImageBitmapLoader( manager ) { + camera.fov = fov; + camera.aspect = aspect; + camera.far = far; + camera.updateProjectionMatrix(); - if ( typeof createImageBitmap === 'undefined' ) { + } - console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); + LightShadow.prototype.updateMatrices.call( this, light ); } - if ( typeof fetch === 'undefined' ) { + } ); - console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); + function SpotLight( color, intensity, distance, angle, penumbra, decay ) { - } + Light.call( this, color, intensity ); - this.manager = manager !== undefined ? manager : DefaultLoadingManager; - this.options = undefined; + this.type = 'SpotLight'; - } + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - ImageBitmapLoader.prototype = { + this.target = new Object3D(); - constructor: ImageBitmapLoader, + Object.defineProperty( this, 'power', { + get: function () { - setOptions: function setOptions( options ) { + // intensity = power per solid angle. + // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf + return this.intensity * Math.PI; - this.options = options; + }, + set: function ( power ) { - return this; + // intensity = power per solid angle. + // ref: equation (17) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf + this.intensity = power / Math.PI; - }, + } + } ); - load: function ( url, onLoad, onProgress, onError ) { + this.distance = ( distance !== undefined ) ? distance : 0; + this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; + this.penumbra = ( penumbra !== undefined ) ? penumbra : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. - if ( url === undefined ) url = ''; + this.shadow = new SpotLightShadow(); - if ( this.path !== undefined ) url = this.path + url; + } - url = this.manager.resolveURL( url ); + SpotLight.prototype = Object.assign( Object.create( Light.prototype ), { - var scope = this; + constructor: SpotLight, - var cached = Cache.get( url ); + isSpotLight: true, - if ( cached !== undefined ) { + copy: function ( source ) { - scope.manager.itemStart( url ); + Light.prototype.copy.call( this, source ); - setTimeout( function () { + this.distance = source.distance; + this.angle = source.angle; + this.penumbra = source.penumbra; + this.decay = source.decay; - if ( onLoad ) onLoad( cached ); + this.target = source.target.clone(); - scope.manager.itemEnd( url ); + this.shadow = source.shadow.clone(); - }, 0 ); + return this; - return cached; + } - } + } ); - fetch( url ).then( function ( res ) { + function PointLightShadow() { - return res.blob(); + LightShadow.call( this, new PerspectiveCamera( 90, 1, 0.5, 500 ) ); - } ).then( function ( blob ) { + this._frameExtents = new Vector2( 4, 2 ); - return createImageBitmap( blob, scope.options ); + this._viewportCount = 6; - } ).then( function ( imageBitmap ) { + 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 ) + ]; - Cache.add( url, imageBitmap ); + 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 ) + ]; - if ( onLoad ) onLoad( imageBitmap ); + 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 ) + ]; - scope.manager.itemEnd( url ); + } - } ).catch( function ( e ) { + PointLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - if ( onError ) onError( e ); + constructor: PointLightShadow, - scope.manager.itemError( url ); - scope.manager.itemEnd( url ); + isPointLightShadow: true, - } ); + updateMatrices: function ( light, viewportIndex ) { - }, + if ( viewportIndex === undefined ) { viewportIndex = 0; } - setCrossOrigin: function ( /* value */ ) { + var camera = this.camera, + shadowMatrix = this.matrix, + lightPositionWorld = this._lightPositionWorld, + lookTarget = this._lookTarget, + projScreenMatrix = this._projScreenMatrix; - return this; + 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(); - setPath: function ( value ) { + shadowMatrix.makeTranslation( - lightPositionWorld.x, - lightPositionWorld.y, - lightPositionWorld.z ); - this.path = value; - return this; + projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + this._frustum.setFromProjectionMatrix( projScreenMatrix ); } - }; + } ); - /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * minimal class for proxing functions to Path. Replaces old "extractSubpaths()" - **/ + function PointLight( color, intensity, distance, decay ) { - function ShapePath() { + Light.call( this, color, intensity ); - this.type = 'ShapePath'; + this.type = 'PointLight'; - this.color = new Color(); + Object.defineProperty( this, 'power', { + get: function () { - this.subPaths = []; - this.currentPath = null; + // intensity = power per solid angle. + // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf + return this.intensity * 4 * Math.PI; + + }, + set: function ( power ) { + + // intensity = power per solid angle. + // ref: equation (15) from https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf + this.intensity = power / ( 4 * Math.PI ); + + } + } ); + + this.distance = ( distance !== undefined ) ? distance : 0; + this.decay = ( decay !== undefined ) ? decay : 1; // for physically correct lights, should be 2. + + this.shadow = new PointLightShadow(); } - Object.assign( ShapePath.prototype, { + PointLight.prototype = Object.assign( Object.create( Light.prototype ), { - moveTo: function ( x, y ) { + constructor: PointLight, - this.currentPath = new Path(); - this.subPaths.push( this.currentPath ); - this.currentPath.moveTo( x, y ); + isPointLight: true, - }, + copy: function ( source ) { - lineTo: function ( x, y ) { + Light.prototype.copy.call( this, source ); - this.currentPath.lineTo( x, y ); + this.distance = source.distance; + this.decay = source.decay; - }, + this.shadow = source.shadow.clone(); - quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { + return this; - this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); + } - }, + } ); - bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + function OrthographicCamera( left, right, top, bottom, near, far ) { - this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); + Camera.call( this ); - }, + this.type = 'OrthographicCamera'; - splineThru: function ( pts ) { + this.zoom = 1; + this.view = null; - this.currentPath.splineThru( pts ); + this.left = ( left !== undefined ) ? left : - 1; + this.right = ( right !== undefined ) ? right : 1; + this.top = ( top !== undefined ) ? top : 1; + this.bottom = ( bottom !== undefined ) ? bottom : - 1; - }, + this.near = ( near !== undefined ) ? near : 0.1; + this.far = ( far !== undefined ) ? far : 2000; - toShapes: function ( isCCW, noHoles ) { + this.updateProjectionMatrix(); - function toShapesNoHoles( inSubpaths ) { + } - var shapes = []; + OrthographicCamera.prototype = Object.assign( Object.create( Camera.prototype ), { - for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) { + constructor: OrthographicCamera, - var tmpPath = inSubpaths[ i ]; + isOrthographicCamera: true, - var tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; + copy: function ( source, recursive ) { - shapes.push( tmpShape ); + Camera.prototype.copy.call( this, 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; - return shapes; + this.zoom = source.zoom; + this.view = source.view === null ? null : Object.assign( {}, source.view ); - } + return this; - function isPointInsidePolygon( inPt, inPolygon ) { + }, - var polyLen = inPolygon.length; + setViewOffset: function ( fullWidth, fullHeight, x, y, width, height ) { - // inPt on polygon contour => immediate success or - // toggling of inside/outside at every single! intersection point of an edge - // with the horizontal line through inPt, left of inPt - // not counting lowerY endpoints of edges and whole edges on that line - var inside = false; - for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { + if ( this.view === null ) { - var edgeLowPt = inPolygon[ p ]; - var edgeHighPt = inPolygon[ q ]; + this.view = { + enabled: true, + fullWidth: 1, + fullHeight: 1, + offsetX: 0, + offsetY: 0, + width: 1, + height: 1 + }; - var edgeDx = edgeHighPt.x - edgeLowPt.x; - var edgeDy = edgeHighPt.y - edgeLowPt.y; + } - if ( Math.abs( edgeDy ) > Number.EPSILON ) { + 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; - // not parallel - if ( edgeDy < 0 ) { + this.updateProjectionMatrix(); - edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; - edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; + }, - } - if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; + clearViewOffset: function () { - if ( inPt.y === edgeLowPt.y ) { + if ( this.view !== null ) { - if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? - // continue; // no intersection or edgeLowPt => doesn't count !!! + this.view.enabled = false; - } else { + } - var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); - if ( perpEdge === 0 ) return true; // inPt is on contour ? - if ( perpEdge < 0 ) continue; - inside = ! inside; // true intersection left of inPt + this.updateProjectionMatrix(); - } + }, - } else { + updateProjectionMatrix: function () { - // 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; + var dx = ( this.right - this.left ) / ( 2 * this.zoom ); + var dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); + var cx = ( this.right + this.left ) / 2; + var cy = ( this.top + this.bottom ) / 2; - } + var left = cx - dx; + var right = cx + dx; + var top = cy + dy; + var bottom = cy - dy; - } + if ( this.view !== null && this.view.enabled ) { - return inside; + var scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; + var 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; } - var isClockWise = ShapeUtils.isClockWise; + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); - var subPaths = this.subPaths; - if ( subPaths.length === 0 ) return []; + this.projectionMatrixInverse.getInverse( this.projectionMatrix ); - if ( noHoles === true ) return toShapesNoHoles( subPaths ); + }, + toJSON: function ( meta ) { - var solid, tmpPath, tmpShape, shapes = []; + var data = Object3D.prototype.toJSON.call( this, meta ); - if ( subPaths.length === 1 ) { + 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; - tmpPath = subPaths[ 0 ]; - tmpShape = new Shape(); - tmpShape.curves = tmpPath.curves; - shapes.push( tmpShape ); - return shapes; + if ( this.view !== null ) { data.object.view = Object.assign( {}, this.view ); } - } + return data; - var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); - holesFirst = isCCW ? ! holesFirst : holesFirst; + } - // console.log("Holes first", holesFirst); + } ); - var betterShapeHoles = []; - var newShapes = []; - var newShapeHoles = []; - var mainIdx = 0; - var tmpPoints; + function DirectionalLightShadow() { - newShapes[ mainIdx ] = undefined; - newShapeHoles[ mainIdx ] = []; + LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); - for ( var i = 0, l = subPaths.length; i < l; i ++ ) { + } - tmpPath = subPaths[ i ]; - tmpPoints = tmpPath.getPoints(); - solid = isClockWise( tmpPoints ); - solid = isCCW ? ! solid : solid; + DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), { - if ( solid ) { + constructor: DirectionalLightShadow, - if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; + isDirectionalLightShadow: true, - newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; - newShapes[ mainIdx ].s.curves = tmpPath.curves; + updateMatrices: function ( light ) { - if ( holesFirst ) mainIdx ++; - newShapeHoles[ mainIdx ] = []; + LightShadow.prototype.updateMatrices.call( this, light ); - //console.log('cw', i); + } - } else { + } ); - newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); + function DirectionalLight( color, intensity ) { - //console.log('ccw', i); + Light.call( this, color, intensity ); - } + this.type = 'DirectionalLight'; - } + this.position.copy( Object3D.DefaultUp ); + this.updateMatrix(); - // only Holes? -> probably all Shapes with wrong orientation - if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); + this.target = new Object3D(); + this.shadow = new DirectionalLightShadow(); - if ( newShapes.length > 1 ) { + } - var ambiguous = false; - var toChange = []; + DirectionalLight.prototype = Object.assign( Object.create( Light.prototype ), { - for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + constructor: DirectionalLight, - betterShapeHoles[ sIdx ] = []; + isDirectionalLight: true, - } + copy: function ( source ) { - for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { + Light.prototype.copy.call( this, source ); - var sho = newShapeHoles[ sIdx ]; + this.target = source.target.clone(); - for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) { + this.shadow = source.shadow.clone(); - var ho = sho[ hIdx ]; - var hole_unassigned = true; + return this; - for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { + } - if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { + } ); - if ( sIdx !== s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); - if ( hole_unassigned ) { + function AmbientLight( color, intensity ) { - hole_unassigned = false; - betterShapeHoles[ s2Idx ].push( ho ); + Light.call( this, color, intensity ); - } else { + this.type = 'AmbientLight'; - ambiguous = true; + this.castShadow = undefined; - } + } - } + AmbientLight.prototype = Object.assign( Object.create( Light.prototype ), { - } - if ( hole_unassigned ) { + constructor: AmbientLight, - betterShapeHoles[ sIdx ].push( ho ); + isAmbientLight: true - } + } ); - } + function RectAreaLight( color, intensity, width, height ) { - } - // console.log("ambiguous: ", ambiguous); - if ( toChange.length > 0 ) { + Light.call( this, color, intensity ); - // console.log("to change: ", toChange); - if ( ! ambiguous ) newShapeHoles = betterShapeHoles; + this.type = 'RectAreaLight'; - } + this.width = ( width !== undefined ) ? width : 10; + this.height = ( height !== undefined ) ? height : 10; - } + } - var tmpHoles; + RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), { - for ( var i = 0, il = newShapes.length; i < il; i ++ ) { + constructor: RectAreaLight, - tmpShape = newShapes[ i ].s; - shapes.push( tmpShape ); - tmpHoles = newShapeHoles[ i ]; + isRectAreaLight: true, - for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) { + copy: function ( source ) { - tmpShape.holes.push( tmpHoles[ j ].h ); + Light.prototype.copy.call( this, source ); - } + this.width = source.width; + this.height = source.height; - } + return this; - //console.log("shape", shapes); + }, - return shapes; + toJSON: function ( meta ) { + + var data = Light.prototype.toJSON.call( this, meta ); + + data.object.width = this.width; + data.object.height = this.height; + + return data; } } ); /** - * @author zz85 / http://www.lab4games.net/zz85/blog - * @author mrdoob / http://mrdoob.com/ + * 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 - function Font( data ) { + function SphericalHarmonics3() { - this.type = 'Font'; + this.coefficients = []; - this.data = data; + for ( var i = 0; i < 9; i ++ ) { - } + this.coefficients.push( new Vector3() ); - Object.assign( Font.prototype, { + } - isFont: true, + } - generateShapes: function ( text, size ) { + Object.assign( SphericalHarmonics3.prototype, { - if ( size === undefined ) size = 100; + isSphericalHarmonics3: true, - var shapes = []; - var paths = createPaths( text, size, this.data ); + set: function ( coefficients ) { - for ( var p = 0, pl = paths.length; p < pl; p ++ ) { + for ( var i = 0; i < 9; i ++ ) { - Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); + this.coefficients[ i ].copy( coefficients[ i ] ); } - return shapes; + return this; - } + }, - } ); + zero: function () { - function createPaths( text, size, data ) { + for ( var i = 0; i < 9; i ++ ) { - var chars = Array.from ? Array.from( text ) : String( text ).split( '' ); // see #13988 - var scale = size / data.resolution; - var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale; + this.coefficients[ i ].set( 0, 0, 0 ); - var paths = []; + } - var offsetX = 0, offsetY = 0; + return this; - for ( var i = 0; i < chars.length; i ++ ) { + }, - var char = chars[ i ]; + // get the radiance in the direction of the normal + // target is a Vector3 + getAt: function ( normal, target ) { - if ( char === '\n' ) { + // normal is assumed to be unit length - offsetX = 0; - offsetY -= line_height; + var x = normal.x, y = normal.y, z = normal.z; - } else { + var coeff = this.coefficients; - var ret = createPath( char, scale, offsetX, offsetY, data ); - offsetX += ret.offsetX; - paths.push( ret.path ); + // 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 paths; + return target; - } + }, - function createPath( char, scale, offsetX, offsetY, data ) { + // 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: function ( normal, target ) { - var glyph = data.glyphs[ char ] || data.glyphs[ '?' ]; + // normal is assumed to be unit length - if ( ! glyph ) return; + var x = normal.x, y = normal.y, z = normal.z; - var path = new ShapePath(); + var coeff = this.coefficients; - var x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2; + // band 0 + target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095 - if ( glyph.o ) { + // 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 ); - var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); + // 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 - for ( var i = 0, l = outline.length; i < l; ) { + return target; - var action = outline[ i ++ ]; + }, - switch ( action ) { + add: function ( sh ) { - case 'm': // moveTo + for ( var i = 0; i < 9; i ++ ) { - x = outline[ i ++ ] * scale + offsetX; - y = outline[ i ++ ] * scale + offsetY; + this.coefficients[ i ].add( sh.coefficients[ i ] ); - path.moveTo( x, y ); + } - break; + return this; - case 'l': // lineTo + }, - x = outline[ i ++ ] * scale + offsetX; - y = outline[ i ++ ] * scale + offsetY; + addScaledSH: function ( sh, s ) { - path.lineTo( x, y ); + for ( var i = 0; i < 9; i ++ ) { - break; + this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); - case 'q': // quadraticCurveTo + } - cpx = outline[ i ++ ] * scale + offsetX; - cpy = outline[ i ++ ] * scale + offsetY; - cpx1 = outline[ i ++ ] * scale + offsetX; - cpy1 = outline[ i ++ ] * scale + offsetY; + return this; - path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); + }, - break; + scale: function ( s ) { - case 'b': // bezierCurveTo + for ( var i = 0; i < 9; i ++ ) { - 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; + this.coefficients[ i ].multiplyScalar( s ); - path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); + } - break; + return this; - } + }, + + lerp: function ( sh, alpha ) { + + for ( var i = 0; i < 9; i ++ ) { + + this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); } - } + return this; - return { offsetX: glyph.ha * scale, path: path }; + }, - } + equals: function ( sh ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + for ( var i = 0; i < 9; i ++ ) { - function FontLoader( manager ) { + if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + return false; - } + } - Object.assign( FontLoader.prototype, { + } - load: function ( url, onLoad, onProgress, onError ) { + return true; - var scope = this; + }, - var loader = new FileLoader( this.manager ); - loader.setPath( this.path ); - loader.load( url, function ( text ) { + copy: function ( sh ) { - var json; + return this.set( sh.coefficients ); - try { + }, - json = JSON.parse( text ); + clone: function () { - } catch ( e ) { + return new this.constructor().copy( this ); - console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' ); - json = JSON.parse( text.substring( 65, text.length - 2 ) ); + }, - } + fromArray: function ( array, offset ) { - var font = scope.parse( json ); + if ( offset === undefined ) { offset = 0; } - if ( onLoad ) onLoad( font ); + var coefficients = this.coefficients; - }, onProgress, onError ); + for ( var i = 0; i < 9; i ++ ) { - }, + coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); - parse: function ( json ) { + } - return new Font( json ); + return this; }, - setPath: function ( value ) { + toArray: function ( array, offset ) { - this.path = value; - return this; + if ( array === undefined ) { array = []; } + if ( offset === undefined ) { offset = 0; } - } + var coefficients = this.coefficients; - } ); + for ( var i = 0; i < 9; i ++ ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + coefficients[ i ].toArray( array, offset + ( i * 3 ) ); - var context; + } - var AudioContext = { + return array; - getContext: function () { + } + + } ); - if ( context === undefined ) { + Object.assign( SphericalHarmonics3, { - context = new ( window.AudioContext || window.webkitAudioContext )(); + // evaluate the basis functions + // shBasis is an Array[ 9 ] + getBasisAt: function ( normal, shBasis ) { - } + // normal is assumed to be unit length - return context; + var x = normal.x, y = normal.y, z = normal.z; - }, + // band 0 + shBasis[ 0 ] = 0.282095; - setContext: function ( value ) { + // band 1 + shBasis[ 1 ] = 0.488603 * y; + shBasis[ 2 ] = 0.488603 * z; + shBasis[ 3 ] = 0.488603 * x; - context = value; + // 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 ); } - }; + } ); - /** - * @author Reece Aaron Lecrivain / http://reecenotes.com/ - */ + function LightProbe( sh, intensity ) { - function AudioLoader( manager ) { + Light.call( this, undefined, intensity ); - this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; + this.type = 'LightProbe'; - } + this.sh = ( sh !== undefined ) ? sh : new SphericalHarmonics3(); - Object.assign( AudioLoader.prototype, { + } - load: function ( url, onLoad, onProgress, onError ) { + LightProbe.prototype = Object.assign( Object.create( Light.prototype ), { - var loader = new FileLoader( this.manager ); - loader.setResponseType( 'arraybuffer' ); - loader.setPath( this.path ); - loader.load( url, function ( buffer ) { + constructor: LightProbe, - // Create a copy of the buffer. The `decodeAudioData` method - // detaches the buffer when complete, preventing reuse. - var bufferCopy = buffer.slice( 0 ); + isLightProbe: true, - var context = AudioContext.getContext(); - context.decodeAudioData( bufferCopy, function ( audioBuffer ) { + copy: function ( source ) { - onLoad( audioBuffer ); + Light.prototype.copy.call( this, source ); - } ); + this.sh.copy( source.sh ); - }, onProgress, onError ); + return this; }, - setPath: function ( value ) { + fromJSON: function ( json ) { + + this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); + this.sh.fromArray( json.sh ); - this.path = value; return this; - } + }, - } ); + toJSON: function ( meta ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + var data = Light.prototype.toJSON.call( this, meta ); - function StereoCamera() { + data.object.sh = this.sh.toArray(); - this.type = 'StereoCamera'; + return data; - this.aspect = 1; + } - this.eyeSep = 0.064; + } ); - this.cameraL = new PerspectiveCamera(); - this.cameraL.layers.enable( 1 ); - this.cameraL.matrixAutoUpdate = false; + function MaterialLoader( manager ) { - this.cameraR = new PerspectiveCamera(); - this.cameraR.layers.enable( 2 ); - this.cameraR.matrixAutoUpdate = false; + Loader.call( this, manager ); + + this.textures = {}; } - Object.assign( StereoCamera.prototype, { + MaterialLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - update: ( function () { + constructor: MaterialLoader, - var instance, focus, fov, aspect, near, far, zoom, eyeSep; + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.load( url, function ( text ) { - var eyeRight = new Matrix4(); - var eyeLeft = new Matrix4(); + try { - return function update( camera ) { + onLoad( scope.parse( JSON.parse( text ) ) ); - var needsUpdate = instance !== this || focus !== camera.focus || fov !== camera.fov || - aspect !== camera.aspect * this.aspect || near !== camera.near || - far !== camera.far || zoom !== camera.zoom || eyeSep !== this.eyeSep; + } catch ( e ) { - if ( needsUpdate ) { + if ( onError ) { - instance = this; - focus = camera.focus; - fov = camera.fov; - aspect = camera.aspect * this.aspect; - near = camera.near; - far = camera.far; - zoom = camera.zoom; + onError( e ); - // Off-axis stereoscopic effect based on - // http://paulbourke.net/stereographics/stereorender/ + } else { - var projectionMatrix = camera.projectionMatrix.clone(); - eyeSep = this.eyeSep / 2; - var eyeSepOnProjection = eyeSep * near / focus; - var ymax = ( near * Math.tan( _Math.DEG2RAD * fov * 0.5 ) ) / zoom; - var xmin, xmax; + console.error( e ); - // translate xOffset + } - eyeLeft.elements[ 12 ] = - eyeSep; - eyeRight.elements[ 12 ] = eyeSep; + scope.manager.itemError( url ); - // for left eye + } - xmin = - ymax * aspect + eyeSepOnProjection; - xmax = ymax * aspect + eyeSepOnProjection; + }, onProgress, onError ); - projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); - projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + }, - this.cameraL.projectionMatrix.copy( projectionMatrix ); + parse: function ( json ) { - // for right eye + var textures = this.textures; - xmin = - ymax * aspect - eyeSepOnProjection; - xmax = ymax * aspect - eyeSepOnProjection; + function getTexture( name ) { - projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin ); - projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); + if ( textures[ name ] === undefined ) { - this.cameraR.projectionMatrix.copy( projectionMatrix ); + console.warn( 'THREE.MaterialLoader: Undefined texture', name ); } - this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft ); - this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight ); + return textures[ name ]; - }; + } - } )() + var material = new Materials[ json.type ](); - } ); + if ( json.uuid !== undefined ) { material.uuid = json.uuid; } + if ( json.name !== undefined ) { material.name = json.name; } + if ( json.color !== undefined ) { material.color.setHex( json.color ); } + if ( json.roughness !== undefined ) { material.roughness = json.roughness; } + if ( json.metalness !== undefined ) { material.metalness = json.metalness; } + if ( json.sheen !== undefined ) { material.sheen = new Color().setHex( json.sheen ); } + if ( json.emissive !== undefined ) { material.emissive.setHex( json.emissive ); } + if ( json.specular !== undefined ) { material.specular.setHex( json.specular ); } + if ( json.shininess !== undefined ) { material.shininess = json.shininess; } + if ( json.clearcoat !== undefined ) { material.clearcoat = json.clearcoat; } + if ( json.clearcoatRoughness !== undefined ) { material.clearcoatRoughness = json.clearcoatRoughness; } + if ( json.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.opacity !== undefined ) { material.opacity = json.opacity; } + if ( json.transparent !== undefined ) { material.transparent = json.transparent; } + if ( json.alphaTest !== undefined ) { material.alphaTest = json.alphaTest; } + if ( json.depthTest !== undefined ) { material.depthTest = json.depthTest; } + if ( json.depthWrite !== undefined ) { material.depthWrite = json.depthWrite; } + if ( json.colorWrite !== undefined ) { material.colorWrite = json.colorWrite; } + + if ( json.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.skinning !== undefined ) { material.skinning = json.skinning; } + if ( json.morphTargets !== undefined ) { material.morphTargets = json.morphTargets; } + if ( json.morphNormals !== undefined ) { material.morphNormals = json.morphNormals; } + if ( json.dithering !== undefined ) { material.dithering = json.dithering; } + + if ( json.vertexTangents !== undefined ) { material.vertexTangents = json.vertexTangents; } + + 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; - /** - * Camera for rendering cube maps - * - renders scene into axis-aligned cube - * - * @author alteredq / http://alteredqualia.com/ - */ + } else { - function CubeCamera( near, far, cubeResolution, options ) { + material.vertexColors = json.vertexColors; - Object3D.call( this ); + } - this.type = 'CubeCamera'; + } - var fov = 90, aspect = 1; + // Shader Material - var cameraPX = new PerspectiveCamera( fov, aspect, near, far ); - cameraPX.up.set( 0, - 1, 0 ); - cameraPX.lookAt( new Vector3( 1, 0, 0 ) ); - this.add( cameraPX ); + if ( json.uniforms !== undefined ) { - var cameraNX = new PerspectiveCamera( fov, aspect, near, far ); - cameraNX.up.set( 0, - 1, 0 ); - cameraNX.lookAt( new Vector3( - 1, 0, 0 ) ); - this.add( cameraNX ); + for ( var name in json.uniforms ) { - var cameraPY = new PerspectiveCamera( fov, aspect, near, far ); - cameraPY.up.set( 0, 0, 1 ); - cameraPY.lookAt( new Vector3( 0, 1, 0 ) ); - this.add( cameraPY ); + var uniform = json.uniforms[ name ]; - var cameraNY = new PerspectiveCamera( fov, aspect, near, far ); - cameraNY.up.set( 0, 0, - 1 ); - cameraNY.lookAt( new Vector3( 0, - 1, 0 ) ); - this.add( cameraNY ); + material.uniforms[ name ] = {}; - var cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraPZ.up.set( 0, - 1, 0 ); - cameraPZ.lookAt( new Vector3( 0, 0, 1 ) ); - this.add( cameraPZ ); + switch ( uniform.type ) { - var cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); - cameraNZ.up.set( 0, - 1, 0 ); - cameraNZ.lookAt( new Vector3( 0, 0, - 1 ) ); - this.add( cameraNZ ); + case 't': + material.uniforms[ name ].value = getTexture( uniform.value ); + break; - options = options || { format: RGBFormat, magFilter: LinearFilter, minFilter: LinearFilter }; + case 'c': + material.uniforms[ name ].value = new Color().setHex( uniform.value ); + break; - this.renderTarget = new WebGLRenderTargetCube( cubeResolution, cubeResolution, options ); - this.renderTarget.texture.name = "CubeCamera"; + case 'v2': + material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); + break; - this.update = function ( renderer, scene ) { + case 'v3': + material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); + break; - if ( this.parent === null ) this.updateMatrixWorld(); + case 'v4': + material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); + break; - var renderTarget = this.renderTarget; - var generateMipmaps = renderTarget.texture.generateMipmaps; + case 'm3': + material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); - renderTarget.texture.generateMipmaps = false; + case 'm4': + material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); + break; - renderTarget.activeCubeFace = 0; - renderer.render( scene, cameraPX, renderTarget ); + default: + material.uniforms[ name ].value = uniform.value; - renderTarget.activeCubeFace = 1; - renderer.render( scene, cameraNX, renderTarget ); + } - renderTarget.activeCubeFace = 2; - renderer.render( scene, cameraPY, renderTarget ); + } - renderTarget.activeCubeFace = 3; - renderer.render( scene, cameraNY, renderTarget ); + } - renderTarget.activeCubeFace = 4; - renderer.render( scene, cameraPZ, renderTarget ); + if ( json.defines !== undefined ) { material.defines = json.defines; } + if ( json.vertexShader !== undefined ) { material.vertexShader = json.vertexShader; } + if ( json.fragmentShader !== undefined ) { material.fragmentShader = json.fragmentShader; } - renderTarget.texture.generateMipmaps = generateMipmaps; + if ( json.extensions !== undefined ) { - renderTarget.activeCubeFace = 5; - renderer.render( scene, cameraNZ, renderTarget ); + for ( var key in json.extensions ) { - renderer.setRenderTarget( null ); + material.extensions[ key ] = json.extensions[ key ]; - }; + } - this.clear = function ( renderer, color, depth, stencil ) { + } - var renderTarget = this.renderTarget; + // Deprecated - for ( var i = 0; i < 6; i ++ ) { + if ( json.shading !== undefined ) { material.flatShading = json.shading === 1; } // THREE.FlatShading - renderTarget.activeCubeFace = i; - renderer.setRenderTarget( renderTarget ); + // for PointsMaterial - renderer.clear( color, depth, stencil ); + if ( json.size !== undefined ) { material.size = json.size; } + if ( json.sizeAttenuation !== undefined ) { material.sizeAttenuation = json.sizeAttenuation; } - } + // maps - renderer.setRenderTarget( null ); + 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; } - CubeCamera.prototype = Object.create( Object3D.prototype ); - CubeCamera.prototype.constructor = CubeCamera; + if ( json.normalMap !== undefined ) { material.normalMap = getTexture( json.normalMap ); } + if ( json.normalMapType !== undefined ) { material.normalMapType = json.normalMapType; } + if ( json.normalScale !== undefined ) { - /** - * @author alteredq / http://alteredqualia.com/ - */ + var normalScale = json.normalScale; - function Clock( autoStart ) { + if ( Array.isArray( normalScale ) === false ) { - this.autoStart = ( autoStart !== undefined ) ? autoStart : true; + // Blender exporter used to export a scalar. See #7459 - this.startTime = 0; - this.oldTime = 0; - this.elapsedTime = 0; + normalScale = [ normalScale, normalScale ]; - this.running = false; + } - } + material.normalScale = new Vector2().fromArray( normalScale ); - Object.assign( Clock.prototype, { + } - start: function () { + 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; } - this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 + if ( json.roughnessMap !== undefined ) { material.roughnessMap = getTexture( json.roughnessMap ); } + if ( json.metalnessMap !== undefined ) { material.metalnessMap = getTexture( json.metalnessMap ); } - this.oldTime = this.startTime; - this.elapsedTime = 0; - this.running = true; + 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 ); } - stop: function () { + if ( json.envMap !== undefined ) { material.envMap = getTexture( json.envMap ); } + if ( json.envMapIntensity !== undefined ) { material.envMapIntensity = json.envMapIntensity; } - this.getElapsedTime(); - this.running = false; - this.autoStart = false; + 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; } - getElapsedTime: function () { + if ( json.aoMap !== undefined ) { material.aoMap = getTexture( json.aoMap ); } + if ( json.aoMapIntensity !== undefined ) { material.aoMapIntensity = json.aoMapIntensity; } - this.getDelta(); - return this.elapsedTime; + 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.transmission !== undefined ) { material.transmission = json.transmission; } + if ( json.transmissionMap !== undefined ) { material.transmissionMap = getTexture( json.transmissionMap ); } + + return material; }, - getDelta: function () { + setTextures: function ( value ) { - var diff = 0; + this.textures = value; + return this; - if ( this.autoStart && ! this.running ) { + } - this.start(); - return 0; + } ); + + var LoaderUtils = { + + decodeText: function ( array ) { + + if ( typeof TextDecoder !== 'undefined' ) { + + return new TextDecoder().decode( array ); } - if ( this.running ) { + // Avoid the String.fromCharCode.apply(null, array) shortcut, which + // throws a "maximum call stack size exceeded" error for large arrays. - var newTime = ( typeof performance === 'undefined' ? Date : performance ).now(); + var s = ''; - diff = ( newTime - this.oldTime ) / 1000; - this.oldTime = newTime; + for ( var i = 0, il = array.length; i < il; i ++ ) { - this.elapsedTime += diff; + // Implicitly assumes little-endian. + s += String.fromCharCode( array[ i ] ); } - return diff; + try { - } + // merges multi-byte utf-8 characters. - } ); + return decodeURIComponent( escape( s ) ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + } catch ( e ) { // see #16358 - function AudioListener() { + return s; - Object3D.call( this ); + } - this.type = 'AudioListener'; + }, - this.context = AudioContext.getContext(); + extractUrlBase: function ( url ) { - this.gain = this.context.createGain(); - this.gain.connect( this.context.destination ); + var index = url.lastIndexOf( '/' ); - this.filter = null; + if ( index === - 1 ) { return './'; } - this.timeDelta = 0; + return url.substr( 0, index + 1 ); - } + } - AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), { + }; - constructor: AudioListener, + function InstancedBufferGeometry() { - getInput: function () { + BufferGeometry.call( this ); - return this.gain; + this.type = 'InstancedBufferGeometry'; + this.instanceCount = Infinity; - }, + } - removeFilter: function ( ) { + InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), { - if ( this.filter !== null ) { + constructor: InstancedBufferGeometry, - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); - this.gain.connect( this.context.destination ); - this.filter = null; + isInstancedBufferGeometry: true, - } + copy: function ( source ) { + + BufferGeometry.prototype.copy.call( this, source ); + + this.instanceCount = source.instanceCount; return this; }, - getFilter: function () { + clone: function () { - return this.filter; + return new this.constructor().copy( this ); }, - setFilter: function ( value ) { + toJSON: function () { - if ( this.filter !== null ) { + var data = BufferGeometry.prototype.toJSON.call( this ); - this.gain.disconnect( this.filter ); - this.filter.disconnect( this.context.destination ); + data.instanceCount = this.instanceCount; - } else { + data.isInstancedBufferGeometry = true; - this.gain.disconnect( this.context.destination ); + return data; - } + } - this.filter = value; - this.gain.connect( this.filter ); - this.filter.connect( this.context.destination ); + } ); - return this; + function InstancedBufferAttribute( array, itemSize, normalized, meshPerAttribute ) { - }, + if ( typeof ( normalized ) === 'number' ) { - getMasterVolume: function () { + meshPerAttribute = normalized; - return this.gain.gain.value; + normalized = false; - }, + console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' ); - setMasterVolume: function ( value ) { + } - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + BufferAttribute.call( this, array, itemSize, normalized ); - return this; + this.meshPerAttribute = meshPerAttribute || 1; - }, + } - updateMatrixWorld: ( function () { + InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), { - var position = new Vector3(); - var quaternion = new Quaternion(); - var scale = new Vector3(); + constructor: InstancedBufferAttribute, - var orientation = new Vector3(); - var clock = new Clock(); + isInstancedBufferAttribute: true, - return function updateMatrixWorld( force ) { + copy: function ( source ) { - Object3D.prototype.updateMatrixWorld.call( this, force ); + BufferAttribute.prototype.copy.call( this, source ); - var listener = this.context.listener; - var up = this.up; + this.meshPerAttribute = source.meshPerAttribute; - this.timeDelta = clock.getDelta(); + return this; - this.matrixWorld.decompose( position, quaternion, scale ); + }, - orientation.set( 0, 0, - 1 ).applyQuaternion( quaternion ); + toJSON: function () { - if ( listener.positionX ) { + var data = BufferAttribute.prototype.toJSON.call( this ); - // code path for Chrome (see #14393) + data.meshPerAttribute = this.meshPerAttribute; - var endTime = this.context.currentTime + this.timeDelta; + data.isInstancedBufferAttribute = true; - listener.positionX.linearRampToValueAtTime( position.x, endTime ); - listener.positionY.linearRampToValueAtTime( position.y, endTime ); - listener.positionZ.linearRampToValueAtTime( position.z, endTime ); - listener.forwardX.linearRampToValueAtTime( orientation.x, endTime ); - listener.forwardY.linearRampToValueAtTime( orientation.y, endTime ); - listener.forwardZ.linearRampToValueAtTime( orientation.z, endTime ); - listener.upX.linearRampToValueAtTime( up.x, endTime ); - listener.upY.linearRampToValueAtTime( up.y, endTime ); - listener.upZ.linearRampToValueAtTime( up.z, endTime ); + return data; - } else { + } - listener.setPosition( position.x, position.y, position.z ); - listener.setOrientation( orientation.x, orientation.y, orientation.z, up.x, up.y, up.z ); + } ); - } + function BufferGeometryLoader( manager ) { - }; + Loader.call( this, manager ); - } )() + } - } ); + BufferGeometryLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - /** - * @author mrdoob / http://mrdoob.com/ - * @author Reece Aaron Lecrivain / http://reecenotes.com/ - */ + constructor: BufferGeometryLoader, - function Audio( listener ) { + load: function ( url, onLoad, onProgress, onError ) { - Object3D.call( this ); + var scope = this; - this.type = 'Audio'; + var loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.load( url, function ( text ) { - this.listener = listener; - this.context = listener.context; + try { - this.gain = this.context.createGain(); - this.gain.connect( listener.getInput() ); + onLoad( scope.parse( JSON.parse( text ) ) ); - this.autoplay = false; + } catch ( e ) { - this.buffer = null; - this.loop = false; - this.startTime = 0; - this.offset = 0; - this.playbackRate = 1; - this.isPlaying = false; - this.hasPlaybackControl = true; - this.sourceType = 'empty'; + if ( onError ) { - this.filters = []; + onError( e ); - } + } else { - Audio.prototype = Object.assign( Object.create( Object3D.prototype ), { + console.error( e ); - constructor: Audio, + } - getOutput: function () { + scope.manager.itemError( url ); - return this.gain; + } + + }, onProgress, onError ); }, - setNodeSource: function ( audioNode ) { + parse: function ( json ) { - this.hasPlaybackControl = false; - this.sourceType = 'audioNode'; - this.source = audioNode; - this.connect(); + var interleavedBufferMap = {}; + var arrayBufferMap = {}; - return this; + function getInterleavedBuffer( json, uuid ) { - }, + if ( interleavedBufferMap[ uuid ] !== undefined ) { return interleavedBufferMap[ uuid ]; } - setMediaElementSource: function ( mediaElement ) { + var interleavedBuffers = json.interleavedBuffers; + var interleavedBuffer = interleavedBuffers[ uuid ]; - this.hasPlaybackControl = false; - this.sourceType = 'mediaNode'; - this.source = this.context.createMediaElementSource( mediaElement ); - this.connect(); + var buffer = getArrayBuffer( json, interleavedBuffer.buffer ); - return this; + var array = new TYPED_ARRAYS[ interleavedBuffer.type ]( buffer ); + var ib = new InterleavedBuffer( array, interleavedBuffer.stride ); + ib.uuid = interleavedBuffer.uuid; - }, + interleavedBufferMap[ uuid ] = ib; - setBuffer: function ( audioBuffer ) { + return ib; - this.buffer = audioBuffer; - this.sourceType = 'buffer'; + } - if ( this.autoplay ) this.play(); + function getArrayBuffer( json, uuid ) { - return this; + if ( arrayBufferMap[ uuid ] !== undefined ) { return arrayBufferMap[ uuid ]; } - }, + var arrayBuffers = json.arrayBuffers; + var arrayBuffer = arrayBuffers[ uuid ]; - play: function () { + var ab = new Uint32Array( arrayBuffer ).buffer; - if ( this.isPlaying === true ) { + arrayBufferMap[ uuid ] = ab; - console.warn( 'THREE.Audio: Audio is already playing.' ); - return; + return ab; } - if ( this.hasPlaybackControl === false ) { + var geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + var index = json.data.index; + + if ( index !== undefined ) { + + var typedArray = new TYPED_ARRAYS[ index.type ]( index.array ); + geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); } - var source = this.context.createBufferSource(); + var attributes = json.data.attributes; - source.buffer = this.buffer; - source.loop = this.loop; - source.onended = this.onEnded.bind( this ); - source.playbackRate.setValueAtTime( this.playbackRate, this.startTime ); - this.startTime = this.context.currentTime; - source.start( this.startTime, this.offset ); + for ( var key in attributes ) { - this.isPlaying = true; + var attribute = attributes[ key ]; + var bufferAttribute = (void 0); - this.source = source; + if ( attribute.isInterleavedBufferAttribute ) { - return this.connect(); + var interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); + bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); - }, + } else { - pause: function () { + var typedArray$1 = new TYPED_ARRAYS[ attribute.type ]( attribute.array ); + var bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; + bufferAttribute = new bufferAttributeConstr( typedArray$1, attribute.itemSize, attribute.normalized ); - if ( this.hasPlaybackControl === false ) { + } - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + if ( attribute.name !== undefined ) { bufferAttribute.name = attribute.name; } + geometry.setAttribute( key, bufferAttribute ); } - if ( this.isPlaying === true ) { + var morphAttributes = json.data.morphAttributes; - this.source.stop(); - this.source.onended = null; - this.offset += ( this.context.currentTime - this.startTime ) * this.playbackRate; - this.isPlaying = false; + if ( morphAttributes ) { - } + for ( var key$1 in morphAttributes ) { - return this; + var attributeArray = morphAttributes[ key$1 ]; - }, + var array = []; - stop: function () { + for ( var i = 0, il = attributeArray.length; i < il; i ++ ) { - if ( this.hasPlaybackControl === false ) { + var attribute$1 = attributeArray[ i ]; + var bufferAttribute$1 = (void 0); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + if ( attribute$1.isInterleavedBufferAttribute ) { - } + var interleavedBuffer$1 = getInterleavedBuffer( json.data, attribute$1.data ); + bufferAttribute$1 = new InterleavedBufferAttribute( interleavedBuffer$1, attribute$1.itemSize, attribute$1.offset, attribute$1.normalized ); - this.source.stop(); - this.source.onended = null; - this.offset = 0; - this.isPlaying = false; - - return this; - - }, + } else { - connect: function () { + var typedArray$2 = new TYPED_ARRAYS[ attribute$1.type ]( attribute$1.array ); + bufferAttribute$1 = new BufferAttribute( typedArray$2, attribute$1.itemSize, attribute$1.normalized ); - if ( this.filters.length > 0 ) { + } - this.source.connect( this.filters[ 0 ] ); + if ( attribute$1.name !== undefined ) { bufferAttribute$1.name = attribute$1.name; } + array.push( bufferAttribute$1 ); - for ( var i = 1, l = this.filters.length; i < l; i ++ ) { + } - this.filters[ i - 1 ].connect( this.filters[ i ] ); + geometry.morphAttributes[ key$1 ] = array; } - this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - - } else { - - this.source.connect( this.getOutput() ); - } - return this; - - }, + var morphTargetsRelative = json.data.morphTargetsRelative; - disconnect: function () { + if ( morphTargetsRelative ) { - if ( this.filters.length > 0 ) { + geometry.morphTargetsRelative = true; - this.source.disconnect( this.filters[ 0 ] ); + } - for ( var i = 1, l = this.filters.length; i < l; i ++ ) { + var groups = json.data.groups || json.data.drawcalls || json.data.offsets; - this.filters[ i - 1 ].disconnect( this.filters[ i ] ); + if ( groups !== undefined ) { - } + for ( var i$1 = 0, n = groups.length; i$1 !== n; ++ i$1 ) { - this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); + var group = groups[ i$1 ]; - } else { + geometry.addGroup( group.start, group.count, group.materialIndex ); - this.source.disconnect( this.getOutput() ); + } } - return this; + var boundingSphere = json.data.boundingSphere; - }, + if ( boundingSphere !== undefined ) { - getFilters: function () { + var center = new Vector3(); - return this.filters; + if ( boundingSphere.center !== undefined ) { - }, + center.fromArray( boundingSphere.center ); - setFilters: function ( value ) { + } - if ( ! value ) value = []; + geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); - if ( this.isPlaying === true ) { + } - this.disconnect(); - this.filters = value; - this.connect(); + if ( json.name ) { geometry.name = json.name; } + if ( json.userData ) { geometry.userData = json.userData; } - } else { + return geometry; - this.filters = value; + } - } + } ); - return this; + var TYPED_ARRAYS = { + Int8Array: Int8Array, + Uint8Array: Uint8Array, + // Workaround for IE11 pre KB2929437. See #11440 + Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array, + Int16Array: Int16Array, + Uint16Array: Uint16Array, + Int32Array: Int32Array, + Uint32Array: Uint32Array, + Float32Array: Float32Array, + Float64Array: Float64Array + }; - }, + function ObjectLoader( manager ) { - getFilter: function () { + Loader.call( this, manager ); - return this.getFilters()[ 0 ]; + } - }, + ObjectLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - setFilter: function ( filter ) { + constructor: ObjectLoader, - return this.setFilters( filter ? [ filter ] : [] ); + load: function ( url, onLoad, onProgress, onError ) { - }, + var scope = this; - setPlaybackRate: function ( value ) { + var path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; + this.resourcePath = this.resourcePath || path; - if ( this.hasPlaybackControl === false ) { + var loader = new FileLoader( scope.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.load( url, function ( text ) { - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + var json = null; - } + try { - this.playbackRate = value; + json = JSON.parse( text ); - if ( this.isPlaying === true ) { + } catch ( error ) { - this.source.playbackRate.setValueAtTime( this.playbackRate, this.context.currentTime ); + if ( onError !== undefined ) { onError( error ); } - } + console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); - return this; + return; - }, + } - getPlaybackRate: function () { + var metadata = json.metadata; - return this.playbackRate; + if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { - }, + console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); + return; - onEnded: function () { + } - this.isPlaying = false; + scope.parse( json, onLoad ); + + }, onProgress, onError ); }, - getLoop: function () { + parse: function ( json, onLoad ) { - if ( this.hasPlaybackControl === false ) { + var shapes = this.parseShape( json.shapes ); + var geometries = this.parseGeometries( json.geometries, shapes ); - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return false; + var images = this.parseImages( json.images, function () { - } + if ( onLoad !== undefined ) { onLoad( object ); } - return this.loop; + } ); - }, + var textures = this.parseTextures( json.textures, images ); + var materials = this.parseMaterials( json.materials, textures ); - setLoop: function ( value ) { + var object = this.parseObject( json.object, geometries, materials ); - if ( this.hasPlaybackControl === false ) { + if ( json.animations ) { - console.warn( 'THREE.Audio: this Audio has no playback control.' ); - return; + object.animations = this.parseAnimations( json.animations ); } - this.loop = value; - - if ( this.isPlaying === true ) { + if ( json.images === undefined || json.images.length === 0 ) { - this.source.loop = this.loop; + if ( onLoad !== undefined ) { onLoad( object ); } } - return this; + return object; }, - getVolume: function () { + parseShape: function ( json ) { - return this.gain.gain.value; + var shapes = {}; - }, + if ( json !== undefined ) { - setVolume: function ( value ) { + for ( var i = 0, l = json.length; i < l; i ++ ) { - this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); + var shape = new Shape().fromJSON( json[ i ] ); - return this; + shapes[ shape.uuid ] = shape; - } + } - } ); + } - /** - * @author mrdoob / http://mrdoob.com/ - */ + return shapes; - function PositionalAudio( listener ) { + }, - Audio.call( this, listener ); + parseGeometries: function ( json, shapes ) { - this.panner = this.context.createPanner(); - this.panner.connect( this.gain ); + var geometries = {}; + var geometryShapes; - } + if ( json !== undefined ) { - PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), { + var bufferGeometryLoader = new BufferGeometryLoader(); - constructor: PositionalAudio, + for ( var i = 0, l = json.length; i < l; i ++ ) { - getOutput: function () { + var geometry = (void 0); + var data = json[ i ]; - return this.panner; + switch ( data.type ) { - }, + case 'PlaneGeometry': + case 'PlaneBufferGeometry': - getRefDistance: function () { + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.widthSegments, + data.heightSegments + ); - return this.panner.refDistance; + break; - }, + case 'BoxGeometry': + case 'BoxBufferGeometry': + case 'CubeGeometry': // backwards compatible - setRefDistance: function ( value ) { + geometry = new Geometries[ data.type ]( + data.width, + data.height, + data.depth, + data.widthSegments, + data.heightSegments, + data.depthSegments + ); - this.panner.refDistance = value; + break; - return this; + case 'CircleGeometry': + case 'CircleBufferGeometry': - }, + geometry = new Geometries[ data.type ]( + data.radius, + data.segments, + data.thetaStart, + data.thetaLength + ); - getRolloffFactor: function () { + break; - return this.panner.rolloffFactor; + case 'CylinderGeometry': + case 'CylinderBufferGeometry': - }, + geometry = new Geometries[ data.type ]( + data.radiusTop, + data.radiusBottom, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); - setRolloffFactor: function ( value ) { + break; - this.panner.rolloffFactor = value; + case 'ConeGeometry': + case 'ConeBufferGeometry': - return this; + geometry = new Geometries[ data.type ]( + data.radius, + data.height, + data.radialSegments, + data.heightSegments, + data.openEnded, + data.thetaStart, + data.thetaLength + ); - }, + break; - getDistanceModel: function () { + case 'SphereGeometry': + case 'SphereBufferGeometry': - return this.panner.distanceModel; + geometry = new Geometries[ data.type ]( + data.radius, + data.widthSegments, + data.heightSegments, + data.phiStart, + data.phiLength, + data.thetaStart, + data.thetaLength + ); - }, + break; - setDistanceModel: function ( value ) { + case 'DodecahedronGeometry': + case 'DodecahedronBufferGeometry': + case 'IcosahedronGeometry': + case 'IcosahedronBufferGeometry': + case 'OctahedronGeometry': + case 'OctahedronBufferGeometry': + case 'TetrahedronGeometry': + case 'TetrahedronBufferGeometry': - this.panner.distanceModel = value; + geometry = new Geometries[ data.type ]( + data.radius, + data.detail + ); - return this; + break; - }, + case 'RingGeometry': + case 'RingBufferGeometry': - getMaxDistance: function () { + geometry = new Geometries[ data.type ]( + data.innerRadius, + data.outerRadius, + data.thetaSegments, + data.phiSegments, + data.thetaStart, + data.thetaLength + ); - return this.panner.maxDistance; + break; - }, + case 'TorusGeometry': + case 'TorusBufferGeometry': - setMaxDistance: function ( value ) { + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.radialSegments, + data.tubularSegments, + data.arc + ); - this.panner.maxDistance = value; + break; - return this; + case 'TorusKnotGeometry': + case 'TorusKnotBufferGeometry': - }, + geometry = new Geometries[ data.type ]( + data.radius, + data.tube, + data.tubularSegments, + data.radialSegments, + data.p, + data.q + ); - setDirectionalCone: function ( coneInnerAngle, coneOuterAngle, coneOuterGain ) { + break; - this.panner.coneInnerAngle = coneInnerAngle; - this.panner.coneOuterAngle = coneOuterAngle; - this.panner.coneOuterGain = coneOuterGain; + case 'TubeGeometry': + case 'TubeBufferGeometry': - return this; + // This only works for built-in curves (e.g. CatmullRomCurve3). + // User defined curves or instances of CurvePath will not be deserialized. + geometry = new Geometries[ data.type ]( + new Curves[ data.path.type ]().fromJSON( data.path ), + data.tubularSegments, + data.radius, + data.radialSegments, + data.closed + ); - }, + break; - updateMatrixWorld: ( function () { + case 'LatheGeometry': + case 'LatheBufferGeometry': - var position = new Vector3(); - var quaternion = new Quaternion(); - var scale = new Vector3(); + geometry = new Geometries[ data.type ]( + data.points, + data.segments, + data.phiStart, + data.phiLength + ); - var orientation = new Vector3(); + break; - return function updateMatrixWorld( force ) { + case 'PolyhedronGeometry': + case 'PolyhedronBufferGeometry': - Object3D.prototype.updateMatrixWorld.call( this, force ); + geometry = new Geometries[ data.type ]( + data.vertices, + data.indices, + data.radius, + data.details + ); - var panner = this.panner; - this.matrixWorld.decompose( position, quaternion, scale ); + break; - orientation.set( 0, 0, 1 ).applyQuaternion( quaternion ); + case 'ShapeGeometry': + case 'ShapeBufferGeometry': - if ( panner.positionX ) { + geometryShapes = []; - // code path for Chrome and Firefox (see #14393) + for ( var j = 0, jl = data.shapes.length; j < jl; j ++ ) { - var endTime = this.context.currentTime + this.listener.timeDelta; + var shape = shapes[ data.shapes[ j ] ]; - 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 ); + geometryShapes.push( shape ); - } else { + } - panner.setPosition( position.x, position.y, position.z ); - panner.setOrientation( orientation.x, orientation.y, orientation.z ); + geometry = new Geometries[ data.type ]( + geometryShapes, + data.curveSegments + ); - } + break; - }; - } )() + case 'ExtrudeGeometry': + case 'ExtrudeBufferGeometry': + geometryShapes = []; - } ); + for ( var j$1 = 0, jl$1 = data.shapes.length; j$1 < jl$1; j$1 ++ ) { - /** - * @author mrdoob / http://mrdoob.com/ - */ + var shape$1 = shapes[ data.shapes[ j$1 ] ]; - function AudioAnalyser( audio, fftSize ) { + geometryShapes.push( shape$1 ); - this.analyser = audio.context.createAnalyser(); - this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048; + } - this.data = new Uint8Array( this.analyser.frequencyBinCount ); + var extrudePath = data.options.extrudePath; - audio.getOutput().connect( this.analyser ); + if ( extrudePath !== undefined ) { - } + data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); - Object.assign( AudioAnalyser.prototype, { + } - getFrequencyData: function () { + geometry = new Geometries[ data.type ]( + geometryShapes, + data.options + ); - this.analyser.getByteFrequencyData( this.data ); + break; - return this.data; + case 'BufferGeometry': + case 'InstancedBufferGeometry': - }, + geometry = bufferGeometryLoader.parse( data ); - getAverageFrequency: function () { + break; - var value = 0, data = this.getFrequencyData(); + case 'Geometry': - for ( var i = 0; i < data.length; i ++ ) { + console.error( 'THREE.ObjectLoader: Loading "Geometry" is not supported anymore.' ); - value += data[ i ]; + break; - } + default: - return value / data.length; + console.warn( 'THREE.ObjectLoader: Unsupported geometry type "' + data.type + '"' ); - } + continue; - } ); + } - /** - * - * Buffered scene graph property that allows weighted accumulation. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + geometry.uuid = data.uuid; - function PropertyMixer( binding, typeName, valueSize ) { + if ( data.name !== undefined ) { geometry.name = data.name; } + if ( geometry.isBufferGeometry === true && data.userData !== undefined ) { geometry.userData = data.userData; } - this.binding = binding; - this.valueSize = valueSize; + geometries[ data.uuid ] = geometry; - var bufferType = Float64Array, - mixFunction; + } - switch ( typeName ) { + } - case 'quaternion': - mixFunction = this._slerp; - break; + return geometries; - case 'string': - case 'bool': - bufferType = Array; - mixFunction = this._select; - break; + }, - default: - mixFunction = this._lerp; + parseMaterials: function ( json, textures ) { - } + var cache = {}; // MultiMaterial + var materials = {}; - this.buffer = new bufferType( valueSize * 4 ); - // layout: [ incoming | accu0 | accu1 | orig ] - // - // 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 + if ( json !== undefined ) { - this._mixBufferRegion = mixFunction; + var loader = new MaterialLoader(); + loader.setTextures( textures ); - this.cumulativeWeight = 0; + for ( var i = 0, l = json.length; i < l; i ++ ) { - this.useCount = 0; - this.referenceCount = 0; + var data = json[ i ]; - } + if ( data.type === 'MultiMaterial' ) { - Object.assign( PropertyMixer.prototype, { + // Deprecated - // accumulate data in the 'incoming' region into 'accu' - accumulate: function ( accuIndex, weight ) { + var array = []; - // note: happily accumulating nothing when weight = 0, the caller knows - // the weight and shouldn't have made the call in the first place + for ( var j = 0; j < data.materials.length; j ++ ) { - var buffer = this.buffer, - stride = this.valueSize, - offset = accuIndex * stride + stride, + var material = data.materials[ j ]; - currentWeight = this.cumulativeWeight; + if ( cache[ material.uuid ] === undefined ) { - if ( currentWeight === 0 ) { + cache[ material.uuid ] = loader.parse( material ); - // accuN := incoming * weight + } - for ( var i = 0; i !== stride; ++ i ) { + array.push( cache[ material.uuid ] ); - buffer[ offset + i ] = buffer[ i ]; + } - } + materials[ data.uuid ] = array; - currentWeight = weight; + } else { - } else { + if ( cache[ data.uuid ] === undefined ) { - // accuN := accuN + incoming * weight + cache[ data.uuid ] = loader.parse( data ); - currentWeight += weight; - var mix = weight / currentWeight; - this._mixBufferRegion( buffer, offset, 0, mix, stride ); + } + + materials[ data.uuid ] = cache[ data.uuid ]; + + } + + } } - this.cumulativeWeight = currentWeight; + return materials; }, - // apply the state of 'accu' to the binding when accus differ - apply: function ( accuIndex ) { + parseAnimations: function ( json ) { - var stride = this.valueSize, - buffer = this.buffer, - offset = accuIndex * stride + stride, + var animations = []; - weight = this.cumulativeWeight, + for ( var i = 0; i < json.length; i ++ ) { - binding = this.binding; + var data = json[ i ]; - this.cumulativeWeight = 0; + var clip = AnimationClip.parse( data ); - if ( weight < 1 ) { + if ( data.uuid !== undefined ) { clip.uuid = data.uuid; } - // accuN := accuN + original * ( 1 - cumulativeWeight ) + animations.push( clip ); - var originalValueOffset = stride * 3; + } - this._mixBufferRegion( - buffer, offset, originalValueOffset, 1 - weight, stride ); + return animations; - } + }, - for ( var i = stride, e = stride + stride; i !== e; ++ i ) { + parseImages: function ( json, onLoad ) { - if ( buffer[ i ] !== buffer[ i + stride ] ) { + var scope = this; + var images = {}; - // value has changed -> update scene graph + var loader; - binding.setValue( buffer, offset ); - break; + function loadImage( url ) { - } + scope.manager.itemStart( url ); - } + return loader.load( url, function () { - }, + scope.manager.itemEnd( url ); - // remember the state of the bound property and copy it to both accus - saveOriginalState: function () { + }, undefined, function () { - var binding = this.binding; + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - var buffer = this.buffer, - stride = this.valueSize, + } ); - originalValueOffset = stride * 3; + } - binding.getValue( buffer, originalValueOffset ); + if ( json !== undefined && json.length > 0 ) { - // accu[0..1] := orig -- initially detect changes against the original - for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) { + var manager = new LoadingManager( onLoad ); - buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; + loader = new ImageLoader( manager ); + loader.setCrossOrigin( this.crossOrigin ); - } + for ( var i = 0, il = json.length; i < il; i ++ ) { - this.cumulativeWeight = 0; + var image = json[ i ]; + var url = image.url; - }, + if ( Array.isArray( url ) ) { - // apply the state previously taken via 'saveOriginalState' to the binding - restoreOriginalState: function () { + // load array of images e.g CubeTexture - var originalValueOffset = this.valueSize * 3; - this.binding.setValue( this.buffer, originalValueOffset ); + images[ image.uuid ] = []; - }, + for ( var j = 0, jl = url.length; j < jl; j ++ ) { + var currentUrl = url[ j ]; - // mix functions + var path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( currentUrl ) ? currentUrl : scope.resourcePath + currentUrl; - _select: function ( buffer, dstOffset, srcOffset, t, stride ) { + images[ image.uuid ].push( loadImage( path ) ); - if ( t >= 0.5 ) { + } - for ( var i = 0; i !== stride; ++ i ) { + } else { - buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; + // load single image - } + var path$1 = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( image.url ) ? image.url : scope.resourcePath + image.url; - } + images[ image.uuid ] = loadImage( path$1 ); - }, + } - _slerp: function ( buffer, dstOffset, srcOffset, t ) { + } - Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); + } + + return images; }, - _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) { + parseTextures: function ( json, images ) { - var s = 1 - t; + function parseConstant( value, type ) { - for ( var i = 0; i !== stride; ++ i ) { + if ( typeof value === 'number' ) { return value; } - var j = dstOffset + i; + console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); - buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; + return type[ value ]; } - } + var textures = {}; - } ); + if ( json !== undefined ) { - /** - * - * A reference to a real property in the scene graph. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + for ( var i = 0, l = json.length; i < l; i ++ ) { - // Characters [].:/ are reserved for track binding syntax. - var RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; + var data = json[ i ]; - function Composite( targetGroup, path, optionalParsedPath ) { + if ( data.image === undefined ) { - var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); + console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); - this._targetGroup = targetGroup; - this._bindings = targetGroup.subscribe_( path, parsedPath ); + } - } + if ( images[ data.image ] === undefined ) { - Object.assign( Composite.prototype, { + console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); - getValue: function ( array, offset ) { + } - this.bind(); // bind all binding + var texture = (void 0); - var firstValidIndex = this._targetGroup.nCachedObjects_, - binding = this._bindings[ firstValidIndex ]; + if ( Array.isArray( images[ data.image ] ) ) { - // and only call .getValue on the first - if ( binding !== undefined ) binding.getValue( array, offset ); + texture = new CubeTexture( images[ data.image ] ); - }, + } else { - setValue: function ( array, offset ) { + texture = new Texture( images[ data.image ] ); - var bindings = this._bindings; + } - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { + texture.needsUpdate = true; - bindings[ i ].setValue( array, offset ); + texture.uuid = data.uuid; - } + if ( data.name !== undefined ) { texture.name = data.name; } - }, + if ( data.mapping !== undefined ) { texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); } - bind: function () { + 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; } - var bindings = this._bindings; + if ( data.wrap !== undefined ) { - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { + texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); + texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); - bindings[ i ].bind(); + } - } + 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; } - unbind: function () { + if ( data.flipY !== undefined ) { texture.flipY = data.flipY; } - var bindings = this._bindings; + if ( data.premultiplyAlpha !== undefined ) { texture.premultiplyAlpha = data.premultiplyAlpha; } + if ( data.unpackAlignment !== undefined ) { texture.unpackAlignment = data.unpackAlignment; } - for ( var i = this._targetGroup.nCachedObjects_, - n = bindings.length; i !== n; ++ i ) { + textures[ data.uuid ] = texture; - bindings[ i ].unbind(); + } } - } + return textures; - } ); + }, + parseObject: function ( data, geometries, materials ) { - function PropertyBinding( rootNode, path, parsedPath ) { + var object; - this.path = path; - this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); + function getGeometry( name ) { - this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; + if ( geometries[ name ] === undefined ) { - this.rootNode = rootNode; + console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); - } + } - Object.assign( PropertyBinding, { + return geometries[ name ]; - Composite: Composite, + } - create: function ( root, path, parsedPath ) { + function getMaterial( name ) { - if ( ! ( root && root.isAnimationObjectGroup ) ) { + if ( name === undefined ) { return undefined; } - return new PropertyBinding( root, path, parsedPath ); + if ( Array.isArray( name ) ) { - } else { + var array = []; - return new PropertyBinding.Composite( root, path, parsedPath ); + for ( var i = 0, l = name.length; i < l; i ++ ) { - } + var uuid = name[ i ]; - }, + if ( materials[ uuid ] === undefined ) { - /** - * 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} - */ - sanitizeNodeName: ( function () { + console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); + + } - var reservedRe = new RegExp( '[' + RESERVED_CHARS_RE + ']', 'g' ); + array.push( materials[ uuid ] ); - return function sanitizeNodeName( name ) { + } - return name.replace( /\s/g, '_' ).replace( reservedRe, '' ); + return array; - }; + } - }() ), + if ( materials[ name ] === undefined ) { - parseTrackName: function () { + console.warn( 'THREE.ObjectLoader: Undefined material', name ); - // 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. - var wordChar = '[^' + RESERVED_CHARS_RE + ']'; - var wordCharOrDot = '[^' + RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; + } - // Parent directories, delimited by '/' or ':'. Currently unused, but must - // be matched to parse the rest of the track name. - var directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', wordChar ); + return materials[ name ]; - // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. - var 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. - var objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', wordChar ); + var geometry, material; - // Property and accessor. May not contain reserved characters. Accessor may - // contain any non-bracket characters. - var propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', wordChar ); + switch ( data.type ) { - var trackRe = new RegExp( '' - + '^' - + directoryRe - + nodeRe - + objectRe - + propertyRe - + '$' - ); + case 'Scene': - var supportedObjectNames = [ 'material', 'materials', 'bones' ]; + object = new Scene(); - return function parseTrackName( trackName ) { + if ( data.background !== undefined ) { - var matches = trackRe.exec( trackName ); + if ( Number.isInteger( data.background ) ) { - if ( ! matches ) { + object.background = new Color( data.background ); - throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); + } - } + } - var results = { - // directoryName: matches[ 1 ], // (tschw) currently unused - nodeName: matches[ 2 ], - objectName: matches[ 3 ], - objectIndex: matches[ 4 ], - propertyName: matches[ 5 ], // required - propertyIndex: matches[ 6 ] - }; + if ( data.fog !== undefined ) { - var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); + if ( data.fog.type === 'Fog' ) { - if ( lastDot !== undefined && lastDot !== - 1 ) { + object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); - var objectName = results.nodeName.substring( lastDot + 1 ); + } else if ( data.fog.type === 'FogExp2' ) { - // Object names must be checked against a whitelist. 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 ) { + object.fog = new FogExp2( data.fog.color, data.fog.density ); - results.nodeName = results.nodeName.substring( 0, lastDot ); - results.objectName = objectName; + } } - } + break; - if ( results.propertyName === null || results.propertyName.length === 0 ) { + case 'PerspectiveCamera': - throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); + 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 ); } - return results; + break; - }; + case 'OrthographicCamera': - }(), + object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); - findNode: function ( root, nodeName ) { + if ( data.zoom !== undefined ) { object.zoom = data.zoom; } + if ( data.view !== undefined ) { object.view = Object.assign( {}, data.view ); } - if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { + break; - return root; + case 'AmbientLight': - } + object = new AmbientLight( data.color, data.intensity ); - // search into skeleton bones. - if ( root.skeleton ) { + break; - var bone = root.skeleton.getBoneByName( nodeName ); + case 'DirectionalLight': - if ( bone !== undefined ) { + object = new DirectionalLight( data.color, data.intensity ); - return bone; + break; - } + case 'PointLight': - } + object = new PointLight( data.color, data.intensity, data.distance, data.decay ); - // search into node subtree. - if ( root.children ) { + break; - var searchNodeSubtree = function ( children ) { + case 'RectAreaLight': - for ( var i = 0; i < children.length; i ++ ) { + object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); - var childNode = children[ i ]; + break; - if ( childNode.name === nodeName || childNode.uuid === nodeName ) { + case 'SpotLight': - return childNode; + object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); - } + break; - var result = searchNodeSubtree( childNode.children ); + case 'HemisphereLight': - if ( result ) return result; + object = new HemisphereLight( data.color, data.groundColor, data.intensity ); - } + break; - return null; + case 'LightProbe': - }; + object = new LightProbe().fromJSON( data ); - var subTreeNode = searchNodeSubtree( root.children ); + break; - if ( subTreeNode ) { + case 'SkinnedMesh': - return subTreeNode; + console.warn( 'THREE.ObjectLoader.parseObject() does not support SkinnedMesh yet.' ); - } + case 'Mesh': - } + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); - return null; + object = new Mesh( geometry, material ); - } + break; - } ); + case 'InstancedMesh': - Object.assign( PropertyBinding.prototype, { // prototype, continued + geometry = getGeometry( data.geometry ); + material = getMaterial( data.material ); + var count = data.count; + var instanceMatrix = data.instanceMatrix; - // these are used to "bind" a nonexistent property - _getValue_unavailable: function () {}, - _setValue_unavailable: function () {}, + object = new InstancedMesh( geometry, material, count ); + object.instanceMatrix = new BufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); - BindingType: { - Direct: 0, - EntireArray: 1, - ArrayElement: 2, - HasFromToArray: 3 - }, + break; - Versioning: { - None: 0, - NeedsUpdate: 1, - MatrixWorldNeedsUpdate: 2 - }, + case 'LOD': - GetterByBindingType: [ + object = new LOD(); - function getValue_direct( buffer, offset ) { + break; - buffer[ offset ] = this.node[ this.propertyName ]; + case 'Line': - }, + object = new Line( getGeometry( data.geometry ), getMaterial( data.material ), data.mode ); - function getValue_array( buffer, offset ) { + break; - var source = this.resolvedProperty; + case 'LineLoop': - for ( var i = 0, n = source.length; i !== n; ++ i ) { + object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); - buffer[ offset ++ ] = source[ i ]; + break; - } + case 'LineSegments': - }, + object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); - function getValue_arrayElement( buffer, offset ) { + break; - buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; + case 'PointCloud': + case 'Points': - }, + object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); - function getValue_toArray( buffer, offset ) { + break; - this.resolvedProperty.toArray( buffer, offset ); + case 'Sprite': - } + object = new Sprite( getMaterial( data.material ) ); - ], + break; - SetterByBindingTypeAndVersioning: [ + case 'Group': - [ - // Direct + object = new Group(); - function setValue_direct( buffer, offset ) { + break; - this.targetObject[ this.propertyName ] = buffer[ offset ]; + default: - }, + object = new Object3D(); - function setValue_direct_setNeedsUpdate( buffer, offset ) { + } - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; + object.uuid = data.uuid; - }, + if ( data.name !== undefined ) { object.name = data.name; } - function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { + if ( data.matrix !== undefined ) { - this.targetObject[ this.propertyName ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; + 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 { - // EntireArray + 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 ); } - function setValue_array( buffer, offset ) { + } - var dest = this.resolvedProperty; + if ( data.castShadow !== undefined ) { object.castShadow = data.castShadow; } + if ( data.receiveShadow !== undefined ) { object.receiveShadow = data.receiveShadow; } - for ( var i = 0, n = dest.length; i !== n; ++ i ) { + if ( data.shadow ) { - dest[ i ] = buffer[ offset ++ ]; + 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; } - function setValue_array_setNeedsUpdate( buffer, offset ) { + if ( data.children !== undefined ) { - var dest = this.resolvedProperty; + var children = data.children; - for ( var i = 0, n = dest.length; i !== n; ++ i ) { + for ( var i = 0; i < children.length; i ++ ) { - dest[ i ] = buffer[ offset ++ ]; + object.add( this.parseObject( children[ i ], geometries, materials ) ); - } + } - this.targetObject.needsUpdate = true; + } - }, + if ( data.type === 'LOD' ) { - function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { + if ( data.autoUpdate !== undefined ) { object.autoUpdate = data.autoUpdate; } - var dest = this.resolvedProperty; + var levels = data.levels; - for ( var i = 0, n = dest.length; i !== n; ++ i ) { + for ( var l = 0; l < levels.length; l ++ ) { - dest[ i ] = buffer[ offset ++ ]; + var level = levels[ l ]; + var child = object.getObjectByProperty( 'uuid', level.object ); - } + if ( child !== undefined ) { - this.targetObject.matrixWorldNeedsUpdate = true; + object.addLevel( child, level.distance ); + + } } - ], [ + } - // ArrayElement + return object; - function setValue_arrayElement( buffer, offset ) { + } - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + } ); - }, + var TEXTURE_MAPPING = { + UVMapping: UVMapping, + CubeReflectionMapping: CubeReflectionMapping, + CubeRefractionMapping: CubeRefractionMapping, + EquirectangularReflectionMapping: EquirectangularReflectionMapping, + EquirectangularRefractionMapping: EquirectangularRefractionMapping, + CubeUVReflectionMapping: CubeUVReflectionMapping, + CubeUVRefractionMapping: CubeUVRefractionMapping + }; - function setValue_arrayElement_setNeedsUpdate( buffer, offset ) { + var TEXTURE_WRAPPING = { + RepeatWrapping: RepeatWrapping, + ClampToEdgeWrapping: ClampToEdgeWrapping, + MirroredRepeatWrapping: MirroredRepeatWrapping + }; - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.needsUpdate = true; + var TEXTURE_FILTER = { + NearestFilter: NearestFilter, + NearestMipmapNearestFilter: NearestMipmapNearestFilter, + NearestMipmapLinearFilter: NearestMipmapLinearFilter, + LinearFilter: LinearFilter, + LinearMipmapNearestFilter: LinearMipmapNearestFilter, + LinearMipmapLinearFilter: LinearMipmapLinearFilter + }; - }, + function ImageBitmapLoader( manager ) { - function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { + if ( typeof createImageBitmap === 'undefined' ) { - this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.targetObject.matrixWorldNeedsUpdate = true; + console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); - } + } - ], [ + if ( typeof fetch === 'undefined' ) { - // HasToFromArray + console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); - function setValue_fromArray( buffer, offset ) { + } - this.resolvedProperty.fromArray( buffer, offset ); + Loader.call( this, manager ); - }, + this.options = { premultiplyAlpha: 'none' }; - function setValue_fromArray_setNeedsUpdate( buffer, offset ) { + } - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.needsUpdate = true; + ImageBitmapLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - }, + constructor: ImageBitmapLoader, - function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { + isImageBitmapLoader: true, - this.resolvedProperty.fromArray( buffer, offset ); - this.targetObject.matrixWorldNeedsUpdate = true; + setOptions: function setOptions( options ) { - } + this.options = options; - ] + return this; - ], + }, - getValue: function getValue_unbound( targetArray, offset ) { + load: function ( url, onLoad, onProgress, onError ) { - this.bind(); - this.getValue( targetArray, offset ); + if ( url === undefined ) { url = ''; } - // 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. + if ( this.path !== undefined ) { url = this.path + url; } - }, + url = this.manager.resolveURL( url ); - setValue: function getValue_unbound( sourceArray, offset ) { + var scope = this; - this.bind(); - this.setValue( sourceArray, offset ); + var cached = Cache.get( url ); - }, + if ( cached !== undefined ) { - // create getter / setter pair for a property in the scene graph - bind: function () { + scope.manager.itemStart( url ); - var targetObject = this.node, - parsedPath = this.parsedPath, + setTimeout( function () { - objectName = parsedPath.objectName, - propertyName = parsedPath.propertyName, - propertyIndex = parsedPath.propertyIndex; + if ( onLoad ) { onLoad( cached ); } - if ( ! targetObject ) { + scope.manager.itemEnd( url ); - targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode; + }, 0 ); - this.node = targetObject; + return cached; } - // set fail state so we can just 'return' on error - this.getValue = this._getValue_unavailable; - this.setValue = this._setValue_unavailable; + fetch( url ).then( function ( res ) { - // ensure there is a value node - if ( ! targetObject ) { + return res.blob(); - console.error( 'THREE.PropertyBinding: Trying to update node for track: ' + this.path + ' but it wasn\'t found.' ); - return; + } ).then( function ( blob ) { - } + return createImageBitmap( blob, scope.options ); - if ( objectName ) { + } ).then( function ( imageBitmap ) { - var objectIndex = parsedPath.objectIndex; + Cache.add( url, imageBitmap ); - // special cases were we need to reach deeper into the hierarchy to get the face materials.... - switch ( objectName ) { + if ( onLoad ) { onLoad( imageBitmap ); } - case 'materials': + scope.manager.itemEnd( url ); - if ( ! targetObject.material ) { + } ).catch( function ( e ) { - console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); - return; + if ( onError ) { onError( e ); } - } + scope.manager.itemError( url ); + scope.manager.itemEnd( url ); - 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; + scope.manager.itemStart( url ); - } + } - targetObject = targetObject.material.materials; + } ); - break; + function ShapePath() { - case 'bones': + this.type = 'ShapePath'; - if ( ! targetObject.skeleton ) { + this.color = new Color(); - console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); - return; + this.subPaths = []; + this.currentPath = null; - } + } - // potential future optimization: skip this if propertyIndex is already an integer - // and convert the integer string to a true integer. + Object.assign( ShapePath.prototype, { - targetObject = targetObject.skeleton.bones; + moveTo: function ( x, y ) { - // support resolving morphTarget names into indices. - for ( var i = 0; i < targetObject.length; i ++ ) { + this.currentPath = new Path(); + this.subPaths.push( this.currentPath ); + this.currentPath.moveTo( x, y ); - if ( targetObject[ i ].name === objectIndex ) { + return this; - objectIndex = i; - break; + }, - } + lineTo: function ( x, y ) { - } + this.currentPath.lineTo( x, y ); - break; + return this; - default: + }, - if ( targetObject[ objectName ] === undefined ) { + quadraticCurveTo: function ( aCPx, aCPy, aX, aY ) { - console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); - return; + this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); - } + return this; - targetObject = targetObject[ objectName ]; + }, - } + bezierCurveTo: function ( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { + this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); - if ( objectIndex !== undefined ) { + return this; - if ( targetObject[ objectIndex ] === undefined ) { + }, - console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); - return; + splineThru: function ( pts ) { - } + this.currentPath.splineThru( pts ); - targetObject = targetObject[ objectIndex ]; + return this; - } + }, - } + toShapes: function ( isCCW, noHoles ) { - // resolve property - var nodeProperty = targetObject[ propertyName ]; + function toShapesNoHoles( inSubpaths ) { - if ( nodeProperty === undefined ) { + var shapes = []; - var nodeName = parsedPath.nodeName; + for ( var i = 0, l = inSubpaths.length; i < l; i ++ ) { - console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + - '.' + propertyName + ' but it wasn\'t found.', targetObject ); - return; + var tmpPath = inSubpaths[ i ]; - } + var tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; - // determine versioning scheme - var versioning = this.Versioning.None; + shapes.push( tmpShape ); - this.targetObject = targetObject; + } - if ( targetObject.needsUpdate !== undefined ) { // material + return shapes; - versioning = this.Versioning.NeedsUpdate; + } - } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + function isPointInsidePolygon( inPt, inPolygon ) { - versioning = this.Versioning.MatrixWorldNeedsUpdate; + var polyLen = inPolygon.length; - } + // inPt on polygon contour => immediate success or + // toggling of inside/outside at every single! intersection point of an edge + // with the horizontal line through inPt, left of inPt + // not counting lowerY endpoints of edges and whole edges on that line + var inside = false; + for ( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { - // determine how the property gets bound - var bindingType = this.BindingType.Direct; + var edgeLowPt = inPolygon[ p ]; + var edgeHighPt = inPolygon[ q ]; - if ( propertyIndex !== undefined ) { + var edgeDx = edgeHighPt.x - edgeLowPt.x; + var edgeDy = edgeHighPt.y - edgeLowPt.y; - // access a sub element of the property array (only primitives are supported right now) + if ( Math.abs( edgeDy ) > Number.EPSILON ) { - if ( propertyName === "morphTargetInfluences" ) { + // not parallel + if ( edgeDy < 0 ) { - // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. + edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; + edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; - // 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 ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) { continue; } - } + if ( inPt.y === edgeLowPt.y ) { - if ( targetObject.geometry.isBufferGeometry ) { + if ( inPt.x === edgeLowPt.x ) { return true; } // inPt is on contour ? + // continue; // no intersection or edgeLowPt => doesn't count !!! - if ( ! targetObject.geometry.morphAttributes ) { + } else { - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); - return; + var perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); + if ( perpEdge === 0 ) { return true; } // inPt is on contour ? + if ( perpEdge < 0 ) { continue; } + inside = ! inside; // true intersection left of inPt } - for ( var i = 0; i < this.node.geometry.morphAttributes.position.length; i ++ ) { + } else { - if ( targetObject.geometry.morphAttributes.position[ i ].name === propertyIndex ) { + // 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; - propertyIndex = i; - break; + } - } + } - } + return inside; + } - } else { + var isClockWise = ShapeUtils.isClockWise; - if ( ! targetObject.geometry.morphTargets ) { + var subPaths = this.subPaths; + if ( subPaths.length === 0 ) { return []; } - console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphTargets.', this ); - return; + if ( noHoles === true ) { return toShapesNoHoles( subPaths ); } - } - for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) { + var solid, tmpPath, tmpShape, shapes = []; - if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) { + if ( subPaths.length === 1 ) { - propertyIndex = i; - break; + tmpPath = subPaths[ 0 ]; + tmpShape = new Shape(); + tmpShape.curves = tmpPath.curves; + shapes.push( tmpShape ); + return shapes; - } + } - } + var holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); + holesFirst = isCCW ? ! holesFirst : holesFirst; - } + // console.log("Holes first", holesFirst); - } + var betterShapeHoles = []; + var newShapes = []; + var newShapeHoles = []; + var mainIdx = 0; + var tmpPoints; - bindingType = this.BindingType.ArrayElement; + newShapes[ mainIdx ] = undefined; + newShapeHoles[ mainIdx ] = []; - this.resolvedProperty = nodeProperty; - this.propertyIndex = propertyIndex; + for ( var i = 0, l = subPaths.length; i < l; i ++ ) { - } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { + tmpPath = subPaths[ i ]; + tmpPoints = tmpPath.getPoints(); + solid = isClockWise( tmpPoints ); + solid = isCCW ? ! solid : solid; - // must use copy for Object3D.Euler/Quaternion + if ( solid ) { - bindingType = this.BindingType.HasFromToArray; + if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) { mainIdx ++; } - this.resolvedProperty = nodeProperty; + newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; + newShapes[ mainIdx ].s.curves = tmpPath.curves; - } else if ( Array.isArray( nodeProperty ) ) { + if ( holesFirst ) { mainIdx ++; } + newShapeHoles[ mainIdx ] = []; - bindingType = this.BindingType.EntireArray; + //console.log('cw', i); - this.resolvedProperty = nodeProperty; + } else { - } else { + newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); - this.propertyName = propertyName; + //console.log('ccw', i); + + } } - // select getter / setter - this.getValue = this.GetterByBindingType[ bindingType ]; - this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; + // only Holes? -> probably all Shapes with wrong orientation + if ( ! newShapes[ 0 ] ) { return toShapesNoHoles( subPaths ); } - }, - unbind: function () { + if ( newShapes.length > 1 ) { - this.node = null; + var ambiguous = false; + var toChange = []; - // 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; + for ( var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { - } + betterShapeHoles[ sIdx ] = []; - } ); + } - //!\ DECLARE ALIAS AFTER assign prototype ! - Object.assign( PropertyBinding.prototype, { + for ( var sIdx$1 = 0, sLen$1 = newShapes.length; sIdx$1 < sLen$1; sIdx$1 ++ ) { - // initial state of these methods that calls 'bind' - _getValue_unbound: PropertyBinding.prototype.getValue, - _setValue_unbound: PropertyBinding.prototype.setValue, + var sho = newShapeHoles[ sIdx$1 ]; - } ); + for ( var hIdx = 0; hIdx < sho.length; hIdx ++ ) { - /** - * - * 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. - * - * @author tschw - */ + var ho = sho[ hIdx ]; + var hole_unassigned = true; - function AnimationObjectGroup() { + for ( var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { - this.uuid = _Math.generateUUID(); + if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { - // cached objects followed by the active ones - this._objects = Array.prototype.slice.call( arguments ); + if ( sIdx$1 !== s2Idx ) { toChange.push( { froms: sIdx$1, tos: s2Idx, hole: hIdx } ); } + if ( hole_unassigned ) { - this.nCachedObjects_ = 0; // threshold - // note: read by PropertyBinding.Composite + hole_unassigned = false; + betterShapeHoles[ s2Idx ].push( ho ); - var indices = {}; - this._indicesByUUID = indices; // for bookkeeping + } else { - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + ambiguous = true; - 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 + } - var scope = this; + if ( hole_unassigned ) { - this.stats = { + betterShapeHoles[ sIdx$1 ].push( ho ); - objects: { - get total() { + } - return scope._objects.length; + } - }, - get inUse() { + } + // console.log("ambiguous: ", ambiguous); - return this.total - scope.nCachedObjects_; + if ( toChange.length > 0 ) { - } - }, - get bindingsPerObject() { + // console.log("to change: ", toChange); + if ( ! ambiguous ) { newShapeHoles = betterShapeHoles; } - return scope._bindings.length; + } } - }; + var tmpHoles; - } + for ( var i$1 = 0, il = newShapes.length; i$1 < il; i$1 ++ ) { - Object.assign( AnimationObjectGroup.prototype, { + tmpShape = newShapes[ i$1 ].s; + shapes.push( tmpShape ); + tmpHoles = newShapeHoles[ i$1 ]; - isAnimationObjectGroup: true, + for ( var j = 0, jl = tmpHoles.length; j < jl; j ++ ) { - add: function () { + tmpShape.holes.push( tmpHoles[ j ].h ); - var objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - indicesByUUID = this._indicesByUUID, - paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - nBindings = bindings.length, - knownObject = undefined; + } - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + } - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + //console.log("shape", shapes); - if ( index === undefined ) { + return shapes; - // 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 + function Font( data ) { - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + this.type = 'Font'; - bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); + this.data = data; - } + } - } else if ( index < nCachedObjects ) { + Object.assign( Font.prototype, { - knownObject = objects[ index ]; + isFont: true, - // move existing object to the ACTIVE region + generateShapes: function ( text, size ) { - var firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ]; + if ( size === undefined ) { size = 100; } - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; + var shapes = []; + var paths = createPaths( text, size, this.data ); - indicesByUUID[ uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = object; + for ( var p = 0, pl = paths.length; p < pl; p ++ ) { - // accounting is done, now do the same for all bindings + Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + } - var bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - binding = bindingsForPath[ index ]; + return shapes; - 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 + function createPaths( text, size, data ) { - binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); + var chars = Array.from ? Array.from( text ) : String( text ).split( '' ); // workaround for IE11, see #13988 + var scale = size / data.resolution; + var line_height = ( data.boundingBox.yMax - data.boundingBox.yMin + data.underlineThickness ) * scale; - } + var paths = []; - bindingsForPath[ firstActiveIndex ] = binding; + var offsetX = 0, offsetY = 0; - } + for ( var i = 0; i < chars.length; i ++ ) { - } else if ( objects[ index ] !== knownObject ) { + var char = chars[ i ]; - console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + - 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); + if ( char === '\n' ) { - } // else the object is already where we want it to be + offsetX = 0; + offsetY -= line_height; - } // for arguments + } else { - this.nCachedObjects_ = nCachedObjects; + var ret = createPath( char, scale, offsetX, offsetY, data ); + offsetX += ret.offsetX; + paths.push( ret.path ); - }, + } - remove: function () { + } - var objects = this._objects, - nCachedObjects = this.nCachedObjects_, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; + return paths; - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + } - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + function createPath( char, scale, offsetX, offsetY, data ) { - if ( index !== undefined && index >= nCachedObjects ) { + var glyph = data.glyphs[ char ] || data.glyphs[ '?' ]; - // move existing object into the CACHED region + if ( ! glyph ) { - var lastCachedIndex = nCachedObjects ++, - firstActiveObject = objects[ lastCachedIndex ]; + console.error( 'THREE.Font: character "' + char + '" does not exists in font family ' + data.familyName + '.' ); - indicesByUUID[ firstActiveObject.uuid ] = index; - objects[ index ] = firstActiveObject; + return; - indicesByUUID[ uuid ] = lastCachedIndex; - objects[ lastCachedIndex ] = object; + } - // accounting is done, now do the same for all bindings + var path = new ShapePath(); - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + var x, y, cpx, cpy, cpx1, cpy1, cpx2, cpy2; - var bindingsForPath = bindings[ j ], - firstActive = bindingsForPath[ lastCachedIndex ], - binding = bindingsForPath[ index ]; + if ( glyph.o ) { - bindingsForPath[ index ] = firstActive; - bindingsForPath[ lastCachedIndex ] = binding; + var outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); - } + for ( var i = 0, l = outline.length; i < l; ) { - } + var action = outline[ i ++ ]; - } // for arguments + switch ( action ) { - this.nCachedObjects_ = nCachedObjects; + case 'm': // moveTo - }, + x = outline[ i ++ ] * scale + offsetX; + y = outline[ i ++ ] * scale + offsetY; - // remove & forget - uncache: function () { + path.moveTo( x, y ); - var objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - indicesByUUID = this._indicesByUUID, - bindings = this._bindings, - nBindings = bindings.length; + break; - for ( var i = 0, n = arguments.length; i !== n; ++ i ) { + case 'l': // lineTo - var object = arguments[ i ], - uuid = object.uuid, - index = indicesByUUID[ uuid ]; + x = outline[ i ++ ] * scale + offsetX; + y = outline[ i ++ ] * scale + offsetY; - if ( index !== undefined ) { + path.lineTo( x, y ); - delete indicesByUUID[ uuid ]; + break; - if ( index < nCachedObjects ) { + case 'q': // quadraticCurveTo - // object is cached, shrink the CACHED region + cpx = outline[ i ++ ] * scale + offsetX; + cpy = outline[ i ++ ] * scale + offsetY; + cpx1 = outline[ i ++ ] * scale + offsetX; + cpy1 = outline[ i ++ ] * scale + offsetY; - var firstActiveIndex = -- nCachedObjects, - lastCachedObject = objects[ firstActiveIndex ], - lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; + path.quadraticCurveTo( cpx1, cpy1, cpx, cpy ); - // last cached object takes this object's place - indicesByUUID[ lastCachedObject.uuid ] = index; - objects[ index ] = lastCachedObject; + break; - // last object goes to the activated slot and pop - indicesByUUID[ lastObject.uuid ] = firstActiveIndex; - objects[ firstActiveIndex ] = lastObject; - objects.pop(); + case 'b': // bezierCurveTo - // accounting is done, now do the same for all bindings + 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; - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy ); - var bindingsForPath = bindings[ j ], - lastCached = bindingsForPath[ firstActiveIndex ], - last = bindingsForPath[ lastIndex ]; + break; - bindingsForPath[ index ] = lastCached; - bindingsForPath[ firstActiveIndex ] = last; - bindingsForPath.pop(); + } - } + } - } else { + } - // object is active, just swap with the last and pop + return { offsetX: glyph.ha * scale, path: path }; - var lastIndex = -- nObjects, - lastObject = objects[ lastIndex ]; + } - indicesByUUID[ lastObject.uuid ] = index; - objects[ index ] = lastObject; - objects.pop(); + function FontLoader( manager ) { - // accounting is done, now do the same for all bindings + Loader.call( this, manager ); - for ( var j = 0, m = nBindings; j !== m; ++ j ) { + } - var bindingsForPath = bindings[ j ]; + FontLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; - bindingsForPath.pop(); + constructor: FontLoader, - } + load: function ( url, onLoad, onProgress, onError ) { - } // cached or active + var scope = this; - } // if object is known + var loader = new FileLoader( this.manager ); + loader.setPath( this.path ); + loader.setRequestHeader( this.requestHeader ); + loader.load( url, function ( text ) { - } // for arguments + var json; - this.nCachedObjects_ = nCachedObjects; + try { - }, + json = JSON.parse( text ); - // Internal interface used by befriended PropertyBinding.Composite: + } catch ( e ) { - subscribe_: function ( path, parsedPath ) { + console.warn( 'THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead.' ); + json = JSON.parse( text.substring( 65, text.length - 2 ) ); - // returns an array of bindings for the given path that is changed - // according to the contained objects in the group + } - var indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ], - bindings = this._bindings; + var font = scope.parse( json ); - if ( index !== undefined ) return bindings[ index ]; + if ( onLoad ) { onLoad( font ); } - var paths = this._paths, - parsedPaths = this._parsedPaths, - objects = this._objects, - nObjects = objects.length, - nCachedObjects = this.nCachedObjects_, - bindingsForPath = new Array( nObjects ); + }, onProgress, onError ); - index = bindings.length; + }, - indicesByPath[ path ] = index; + parse: function ( json ) { - paths.push( path ); - parsedPaths.push( parsedPath ); - bindings.push( bindingsForPath ); + return new Font( json ); - for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) { + } - var object = objects[ i ]; - bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); + } ); + + var _context; + + var AudioContext = { + + getContext: function () { + + if ( _context === undefined ) { + + _context = new ( window.AudioContext || window.webkitAudioContext )(); } - return bindingsForPath; + return _context; }, - unsubscribe_: function ( path ) { + setContext: function ( value ) { - // tells the group to forget about a property path and no longer - // update the array previously obtained with 'subscribe_' + _context = value; - var indicesByPath = this._bindingsIndicesByPath, - index = indicesByPath[ path ]; + } - if ( index !== undefined ) { + }; - var paths = this._paths, - parsedPaths = this._parsedPaths, - bindings = this._bindings, - lastBindingsIndex = bindings.length - 1, - lastBindings = bindings[ lastBindingsIndex ], - lastBindingsPath = path[ lastBindingsIndex ]; + function AudioLoader( manager ) { - indicesByPath[ lastBindingsPath ] = index; + Loader.call( this, manager ); - bindings[ index ] = lastBindings; - bindings.pop(); + } - parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; - parsedPaths.pop(); + AudioLoader.prototype = Object.assign( Object.create( Loader.prototype ), { - paths[ index ] = paths[ lastBindingsIndex ]; - paths.pop(); + constructor: AudioLoader, - } + load: function ( url, onLoad, onProgress, onError ) { - } + var scope = this; - } ); + var loader = new FileLoader( scope.manager ); + loader.setResponseType( 'arraybuffer' ); + loader.setPath( scope.path ); + loader.setRequestHeader( scope.requestHeader ); + loader.load( url, function ( buffer ) { - /** - * - * Action provided by AnimationMixer for scheduling clip playback on specific - * objects. - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - * - */ + try { - function AnimationAction( mixer, clip, localRoot ) { + // Create a copy of the buffer. The `decodeAudioData` method + // detaches the buffer when complete, preventing reuse. + var bufferCopy = buffer.slice( 0 ); - this._mixer = mixer; - this._clip = clip; - this._localRoot = localRoot || null; + var context = AudioContext.getContext(); + context.decodeAudioData( bufferCopy, function ( audioBuffer ) { - var tracks = clip.tracks, - nTracks = tracks.length, - interpolants = new Array( nTracks ); + onLoad( audioBuffer ); - var interpolantSettings = { - endingStart: ZeroCurvatureEnding, - endingEnd: ZeroCurvatureEnding - }; + } ); - for ( var i = 0; i !== nTracks; ++ i ) { + } catch ( e ) { - var interpolant = tracks[ i ].createInterpolant( null ); - interpolants[ i ] = interpolant; - interpolant.settings = interpolantSettings; + if ( onError ) { - } + onError( e ); - this._interpolantSettings = interpolantSettings; + } else { - this._interpolants = interpolants; // bound by the mixer + console.error( e ); - // 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 + scope.manager.itemError( url ); - this._timeScaleInterpolant = null; - this._weightInterpolant = null; + } - this.loop = LoopRepeat; - this._loopCount = - 1; + }, onProgress, onError ); - // 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; + function HemisphereLightProbe( skyColor, groundColor, intensity ) { - this.weight = 1; - this._effectiveWeight = 1; + LightProbe.call( this, undefined, intensity ); - this.repetitions = Infinity; // no. of repetitions when looping + var color1 = new Color().set( skyColor ); + var color2 = new Color().set( groundColor ); - this.paused = false; // true -> zero effective time scale - this.enabled = true; // false -> zero effective weight + var sky = new Vector3( color1.r, color1.g, color1.b ); + var ground = new Vector3( color2.r, color2.g, color2.b ); - this.clampWhenFinished = false; // keep feeding the last frame? + // without extra factor of PI in the shader, should = 1 / Math.sqrt( Math.PI ); + var c0 = Math.sqrt( Math.PI ); + var c1 = c0 * Math.sqrt( 0.75 ); - this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate - this.zeroSlopeAtEnd = true; // clips for start, loop and end + this.sh.coefficients[ 0 ].copy( sky ).add( ground ).multiplyScalar( c0 ); + this.sh.coefficients[ 1 ].copy( sky ).sub( ground ).multiplyScalar( c1 ); } - Object.assign( AnimationAction.prototype, { + HemisphereLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), { - // State & Scheduling + constructor: HemisphereLightProbe, - play: function () { + isHemisphereLightProbe: true, - this._mixer._activateAction( this ); + copy: function ( source ) { // modifying colors not currently supported + + LightProbe.prototype.copy.call( this, source ); return this; }, - stop: function () { - - this._mixer._deactivateAction( this ); + toJSON: function ( meta ) { - return this.reset(); + var data = LightProbe.prototype.toJSON.call( this, meta ); - }, + // data.sh = this.sh.toArray(); // todo - reset: function () { + return data; - 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(); + function AmbientLightProbe( color, intensity ) { - }, + LightProbe.call( this, undefined, intensity ); - isRunning: function () { + var color1 = new Color().set( color ); - return this.enabled && ! this.paused && this.timeScale !== 0 && - this._startTime === null && this._mixer._isActiveAction( this ); + // 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 ) ); - }, + } - // return true when play has been called - isScheduled: function () { + AmbientLightProbe.prototype = Object.assign( Object.create( LightProbe.prototype ), { - return this._mixer._isActiveAction( this ); + constructor: AmbientLightProbe, - }, + isAmbientLightProbe: true, - startAt: function ( time ) { + copy: function ( source ) { // modifying color not currently supported - this._startTime = time; + LightProbe.prototype.copy.call( this, source ); return this; }, - setLoop: function ( mode, repetitions ) { - - this.loop = mode; - this.repetitions = repetitions; - - return this; + toJSON: function ( meta ) { - }, + var data = LightProbe.prototype.toJSON.call( this, meta ); - // Weight + // data.sh = this.sh.toArray(); // todo - // 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: function ( weight ) { + return data; - this.weight = weight; + } - // note: same logic as when updated at runtime - this._effectiveWeight = this.enabled ? weight : 0; + } ); - return this.stopFading(); + var _eyeRight = new Matrix4(); + var _eyeLeft = new Matrix4(); - }, + function StereoCamera() { - // return the weight considering fading and .enabled - getEffectiveWeight: function () { + this.type = 'StereoCamera'; - return this._effectiveWeight; + this.aspect = 1; - }, + this.eyeSep = 0.064; - fadeIn: function ( duration ) { + this.cameraL = new PerspectiveCamera(); + this.cameraL.layers.enable( 1 ); + this.cameraL.matrixAutoUpdate = false; - return this._scheduleFading( duration, 0, 1 ); + 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 + }; - fadeOut: function ( duration ) { + } - return this._scheduleFading( duration, 1, 0 ); + Object.assign( StereoCamera.prototype, { - }, + update: function ( camera ) { - crossFadeFrom: function ( fadeOutAction, duration, warp ) { + var cache = this._cache; - fadeOutAction.fadeOut( duration ); - this.fadeIn( duration ); + var 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 ( warp ) { + if ( needsUpdate ) { - var fadeInDuration = this._clip.duration, - fadeOutDuration = fadeOutAction._clip.duration, + 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; - startEndRatio = fadeOutDuration / fadeInDuration, - endStartRatio = fadeInDuration / fadeOutDuration; + // Off-axis stereoscopic effect based on + // http://paulbourke.net/stereographics/stereorender/ - fadeOutAction.warp( 1.0, startEndRatio, duration ); - this.warp( endStartRatio, 1.0, duration ); + var projectionMatrix = camera.projectionMatrix.clone(); + var eyeSepHalf = cache.eyeSep / 2; + var eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; + var ymax = ( cache.near * Math.tan( MathUtils.DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; + var xmin, xmax; - } + // translate xOffset - return this; + _eyeLeft.elements[ 12 ] = - eyeSepHalf; + _eyeRight.elements[ 12 ] = eyeSepHalf; - }, + // for left eye - crossFadeTo: function ( fadeInAction, duration, warp ) { + xmin = - ymax * cache.aspect + eyeSepOnProjection; + xmax = ymax * cache.aspect + eyeSepOnProjection; - return fadeInAction.crossFadeFrom( this, duration, warp ); + projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); + projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - }, + this.cameraL.projectionMatrix.copy( projectionMatrix ); - stopFading: function () { + // for right eye - var weightInterpolant = this._weightInterpolant; + xmin = - ymax * cache.aspect - eyeSepOnProjection; + xmax = ymax * cache.aspect - eyeSepOnProjection; - if ( weightInterpolant !== null ) { + projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); + projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); - this._weightInterpolant = null; - this._mixer._takeBackControlInterpolant( weightInterpolant ); + this.cameraR.projectionMatrix.copy( projectionMatrix ); } - return this; - - }, + this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); + this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); - // 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: function ( timeScale ) { + } ); - this.timeScale = timeScale; - this._effectiveTimeScale = this.paused ? 0 : timeScale; + function Clock( autoStart ) { - return this.stopWarping(); + this.autoStart = ( autoStart !== undefined ) ? autoStart : true; - }, + this.startTime = 0; + this.oldTime = 0; + this.elapsedTime = 0; - // return the time scale considering warping and .paused - getEffectiveTimeScale: function () { + this.running = false; - return this._effectiveTimeScale; + } - }, + Object.assign( Clock.prototype, { - setDuration: function ( duration ) { + start: function () { - this.timeScale = this._clip.duration / duration; + this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 - return this.stopWarping(); + this.oldTime = this.startTime; + this.elapsedTime = 0; + this.running = true; }, - syncWith: function ( action ) { - - this.time = action.time; - this.timeScale = action.timeScale; + stop: function () { - return this.stopWarping(); + this.getElapsedTime(); + this.running = false; + this.autoStart = false; }, - halt: function ( duration ) { + getElapsedTime: function () { - return this.warp( this._effectiveTimeScale, 0, duration ); + this.getDelta(); + return this.elapsedTime; }, - warp: function ( startTimeScale, endTimeScale, duration ) { - - var mixer = this._mixer, now = mixer.time, - interpolant = this._timeScaleInterpolant, + getDelta: function () { - timeScale = this.timeScale; + var diff = 0; - if ( interpolant === null ) { + if ( this.autoStart && ! this.running ) { - interpolant = mixer._lendControlInterpolant(); - this._timeScaleInterpolant = interpolant; + this.start(); + return 0; } - var times = interpolant.parameterPositions, - values = interpolant.sampleValues; - - times[ 0 ] = now; - times[ 1 ] = now + duration; + if ( this.running ) { - values[ 0 ] = startTimeScale / timeScale; - values[ 1 ] = endTimeScale / timeScale; + var newTime = ( typeof performance === 'undefined' ? Date : performance ).now(); - return this; + diff = ( newTime - this.oldTime ) / 1000; + this.oldTime = newTime; - }, + this.elapsedTime += diff; - stopWarping: function () { + } - var timeScaleInterpolant = this._timeScaleInterpolant; + return diff; - if ( timeScaleInterpolant !== null ) { + } - this._timeScaleInterpolant = null; - this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); + } ); - } + var _position$2 = new Vector3(); + var _quaternion$3 = new Quaternion(); + var _scale$1 = new Vector3(); + var _orientation = new Vector3(); - return this; + function AudioListener() { - }, + Object3D.call( this ); - // Object Accessors + this.type = 'AudioListener'; - getMixer: function () { + this.context = AudioContext.getContext(); - return this._mixer; + this.gain = this.context.createGain(); + this.gain.connect( this.context.destination ); - }, + this.filter = null; - getClip: function () { + this.timeDelta = 0; - return this._clip; + // private - }, + this._clock = new Clock(); - getRoot: function () { + } - return this._localRoot || this._mixer._root; + AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), { - }, + constructor: AudioListener, - // Interna + getInput: function () { - _update: function ( time, deltaTime, timeDirection, accuIndex ) { + return this.gain; - // called by the mixer + }, - if ( ! this.enabled ) { + removeFilter: function ( ) { - // call ._updateWeight() to update ._effectiveWeight + if ( this.filter !== null ) { - this._updateWeight( time ); - return; + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); + this.gain.connect( this.context.destination ); + this.filter = null; } - var startTime = this._startTime; - - if ( startTime !== null ) { + return this; - // check for scheduled start of action + }, - var timeRunning = ( time - startTime ) * timeDirection; - if ( timeRunning < 0 || timeDirection === 0 ) { + getFilter: function () { - return; // yet to come / don't decide when delta = 0 + return this.filter; - } + }, - // start + setFilter: function ( value ) { - this._startTime = null; // unschedule - deltaTime = timeDirection * timeRunning; + if ( this.filter !== null ) { - } + this.gain.disconnect( this.filter ); + this.filter.disconnect( this.context.destination ); - // apply time scale and advance time + } else { - deltaTime *= this._updateTimeScale( time ); - var clipTime = this._updateTime( deltaTime ); + this.gain.disconnect( this.context.destination ); - // note: _updateTime may disable the action resulting in - // an effective weight of 0 + } - var weight = this._updateWeight( time ); + this.filter = value; + this.gain.connect( this.filter ); + this.filter.connect( this.context.destination ); - if ( weight > 0 ) { + return this; - var interpolants = this._interpolants; - var propertyMixers = this._propertyBindings; + }, - for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { + getMasterVolume: function () { - interpolants[ j ].evaluate( clipTime ); - propertyMixers[ j ].accumulate( accuIndex, weight ); + return this.gain.gain.value; - } + }, - } + setMasterVolume: function ( value ) { - }, + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - _updateWeight: function ( time ) { + return this; - var weight = 0; + }, - if ( this.enabled ) { + updateMatrixWorld: function ( force ) { - weight = this.weight; - var interpolant = this._weightInterpolant; + Object3D.prototype.updateMatrixWorld.call( this, force ); - if ( interpolant !== null ) { + var listener = this.context.listener; + var up = this.up; - var interpolantValue = interpolant.evaluate( time )[ 0 ]; + this.timeDelta = this._clock.getDelta(); - weight *= interpolantValue; + this.matrixWorld.decompose( _position$2, _quaternion$3, _scale$1 ); - if ( time > interpolant.parameterPositions[ 1 ] ) { + _orientation.set( 0, 0, - 1 ).applyQuaternion( _quaternion$3 ); - this.stopFading(); + if ( listener.positionX ) { - if ( interpolantValue === 0 ) { + // code path for Chrome (see #14393) - // faded out, disable - this.enabled = false; + var endTime = this.context.currentTime + this.timeDelta; - } + listener.positionX.linearRampToValueAtTime( _position$2.x, endTime ); + listener.positionY.linearRampToValueAtTime( _position$2.y, endTime ); + listener.positionZ.linearRampToValueAtTime( _position$2.z, endTime ); + listener.forwardX.linearRampToValueAtTime( _orientation.x, endTime ); + listener.forwardY.linearRampToValueAtTime( _orientation.y, endTime ); + listener.forwardZ.linearRampToValueAtTime( _orientation.z, endTime ); + listener.upX.linearRampToValueAtTime( up.x, endTime ); + listener.upY.linearRampToValueAtTime( up.y, endTime ); + listener.upZ.linearRampToValueAtTime( up.z, endTime ); - } + } else { - } + listener.setPosition( _position$2.x, _position$2.y, _position$2.z ); + listener.setOrientation( _orientation.x, _orientation.y, _orientation.z, up.x, up.y, up.z ); } - this._effectiveWeight = weight; - return weight; - - }, + } - _updateTimeScale: function ( time ) { + } ); - var timeScale = 0; + function Audio( listener ) { - if ( ! this.paused ) { + Object3D.call( this ); - timeScale = this.timeScale; + this.type = 'Audio'; - var interpolant = this._timeScaleInterpolant; + this.listener = listener; + this.context = listener.context; - if ( interpolant !== null ) { + this.gain = this.context.createGain(); + this.gain.connect( listener.getInput() ); - var interpolantValue = interpolant.evaluate( time )[ 0 ]; + this.autoplay = false; - timeScale *= interpolantValue; + 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.sourceType = 'empty'; - if ( time > interpolant.parameterPositions[ 1 ] ) { + this._startedAt = 0; + this._progress = 0; - this.stopWarping(); + this.filters = []; - if ( timeScale === 0 ) { + } - // motion has halted, pause - this.paused = true; + Audio.prototype = Object.assign( Object.create( Object3D.prototype ), { - } else { + constructor: Audio, - // warp done - apply final time scale - this.timeScale = timeScale; + getOutput: function () { - } + return this.gain; - } + }, - } + setNodeSource: function ( audioNode ) { - } + this.hasPlaybackControl = false; + this.sourceType = 'audioNode'; + this.source = audioNode; + this.connect(); - this._effectiveTimeScale = timeScale; - return timeScale; + return this; }, - _updateTime: function ( deltaTime ) { + setMediaElementSource: function ( mediaElement ) { - var time = this.time + deltaTime; - var duration = this._clip.duration; - var loop = this.loop; - var loopCount = this._loopCount; + this.hasPlaybackControl = false; + this.sourceType = 'mediaNode'; + this.source = this.context.createMediaElementSource( mediaElement ); + this.connect(); - var pingPong = ( loop === LoopPingPong ); + return this; - if ( deltaTime === 0 ) { + }, - if ( loopCount === - 1 ) return time; + setMediaStreamSource: function ( mediaStream ) { - return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; + this.hasPlaybackControl = false; + this.sourceType = 'mediaStreamNode'; + this.source = this.context.createMediaStreamSource( mediaStream ); + this.connect(); - } + return this; - if ( loop === LoopOnce ) { + }, - if ( loopCount === - 1 ) { + setBuffer: function ( audioBuffer ) { - // just started + this.buffer = audioBuffer; + this.sourceType = 'buffer'; - this._loopCount = 0; - this._setEndings( true, true, false ); + if ( this.autoplay ) { this.play(); } - } + return this; - handle_stop: { + }, - if ( time >= duration ) { + play: function ( delay ) { - time = duration; + if ( delay === undefined ) { delay = 0; } - } else if ( time < 0 ) { + if ( this.isPlaying === true ) { - time = 0; + console.warn( 'THREE.Audio: Audio is already playing.' ); + return; - } else break handle_stop; + } - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; + if ( this.hasPlaybackControl === false ) { - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime < 0 ? - 1 : 1 - } ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - } + } - } else { // repetitive Repeat or PingPong + this._startedAt = this.context.currentTime + delay; - if ( loopCount === - 1 ) { + var 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 ); - // just started + this.isPlaying = true; - if ( deltaTime >= 0 ) { + this.source = source; - loopCount = 0; + this.setDetune( this.detune ); + this.setPlaybackRate( this.playbackRate ); - this._setEndings( true, this.repetitions === 0, pingPong ); + return this.connect(); - } else { + }, - // when looping in reverse direction, the initial - // transition through zero counts as a repetition, - // so leave loopCount at -1 + pause: function () { - this._setEndings( this.repetitions === 0, true, pingPong ); + if ( this.hasPlaybackControl === false ) { - } + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - } + } - if ( time >= duration || time < 0 ) { + if ( this.isPlaying === true ) { - // wrap around + // update current progress - var loopDelta = Math.floor( time / duration ); // signed - time -= duration * loopDelta; + this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; - loopCount += Math.abs( loopDelta ); + if ( this.loop === true ) { - var pending = this.repetitions - loopCount; + // ensure _progress does not exceed duration with looped audios - if ( pending <= 0 ) { + this._progress = this._progress % ( this.duration || this.buffer.duration ); - // have to stop (switch state, clamp time, fire event) + } - if ( this.clampWhenFinished ) this.paused = true; - else this.enabled = false; + this.source.stop(); + this.source.onended = null; - time = deltaTime > 0 ? duration : 0; + this.isPlaying = false; - this._mixer.dispatchEvent( { - type: 'finished', action: this, - direction: deltaTime > 0 ? 1 : - 1 - } ); + } - } else { + return this; - // keep running + }, - if ( pending === 1 ) { + stop: function () { - // entering the last round + if ( this.hasPlaybackControl === false ) { - var atStart = deltaTime < 0; - this._setEndings( atStart, ! atStart, pingPong ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - } else { + } - this._setEndings( false, false, pingPong ); + this._progress = 0; - } + this.source.stop(); + this.source.onended = null; + this.isPlaying = false; - this._loopCount = loopCount; + return this; - this._mixer.dispatchEvent( { - type: 'loop', action: this, loopDelta: loopDelta - } ); + }, - } + connect: function () { - } + if ( this.filters.length > 0 ) { - if ( pingPong && ( loopCount & 1 ) === 1 ) { + this.source.connect( this.filters[ 0 ] ); - // invert time for the "pong round" + for ( var i = 1, l = this.filters.length; i < l; i ++ ) { - this.time = time; - return duration - time; + this.filters[ i - 1 ].connect( this.filters[ i ] ); } - } - - this.time = time; - return time; - - }, + this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); - _setEndings: function ( atStart, atEnd, pingPong ) { + } else { - var settings = this._interpolantSettings; + this.source.connect( this.getOutput() ); - if ( pingPong ) { + } - settings.endingStart = ZeroSlopeEnding; - settings.endingEnd = ZeroSlopeEnding; + return this; - } else { + }, - // assuming for LoopOnce atStart == atEnd == true + disconnect: function () { - if ( atStart ) { + if ( this.filters.length > 0 ) { - settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; + this.source.disconnect( this.filters[ 0 ] ); - } else { + for ( var i = 1, l = this.filters.length; i < l; i ++ ) { - settings.endingStart = WrapAroundEnding; + this.filters[ i - 1 ].disconnect( this.filters[ i ] ); } - if ( atEnd ) { - - settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; - - } else { + this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); - settings.endingEnd = WrapAroundEnding; + } else { - } + this.source.disconnect( this.getOutput() ); } - }, - - _scheduleFading: function ( duration, weightNow, weightThen ) { + return this; - var mixer = this._mixer, now = mixer.time, - interpolant = this._weightInterpolant; + }, - if ( interpolant === null ) { + getFilters: function () { - interpolant = mixer._lendControlInterpolant(); - this._weightInterpolant = interpolant; + return this.filters; - } + }, - var times = interpolant.parameterPositions, - values = interpolant.sampleValues; + setFilters: function ( value ) { - times[ 0 ] = now; values[ 0 ] = weightNow; - times[ 1 ] = now + duration; values[ 1 ] = weightThen; + if ( ! value ) { value = []; } - return this; + if ( this.isPlaying === true ) { - } + this.disconnect(); + this.filters = value; + this.connect(); - } ); + } else { - /** - * - * Player for AnimationClips. - * - * - * @author Ben Houston / http://clara.io/ - * @author David Sarno / http://lighthaus.us/ - * @author tschw - */ + this.filters = value; - function AnimationMixer( root ) { + } - this._root = root; - this._initMemoryManager(); - this._accuIndex = 0; + return this; - this.time = 0; + }, - this.timeScale = 1.0; + setDetune: function ( value ) { - } + this.detune = value; - AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { + if ( this.source.detune === undefined ) { return; } // only set detune when available - constructor: AnimationMixer, + if ( this.isPlaying === true ) { - _bindAction: function ( action, prototypeAction ) { + this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); - var root = action._localRoot || this._root, - tracks = action._clip.tracks, - nTracks = tracks.length, - bindings = action._propertyBindings, - interpolants = action._interpolants, - rootUuid = root.uuid, - bindingsByRoot = this._bindingsByRootAndName, - bindingsByName = bindingsByRoot[ rootUuid ]; + } - if ( bindingsByName === undefined ) { + return this; - bindingsByName = {}; - bindingsByRoot[ rootUuid ] = bindingsByName; + }, - } + getDetune: function () { - for ( var i = 0; i !== nTracks; ++ i ) { + return this.detune; - var track = tracks[ i ], - trackName = track.name, - binding = bindingsByName[ trackName ]; + }, - if ( binding !== undefined ) { + getFilter: function () { - bindings[ i ] = binding; + return this.getFilters()[ 0 ]; - } else { + }, - binding = bindings[ i ]; + setFilter: function ( filter ) { - if ( binding !== undefined ) { + return this.setFilters( filter ? [ filter ] : [] ); - // existing binding, make sure the cache knows + }, - if ( binding._cacheIndex === null ) { + setPlaybackRate: function ( value ) { - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); + if ( this.hasPlaybackControl === false ) { - } + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - continue; + } - } + this.playbackRate = value; - var path = prototypeAction && prototypeAction. - _propertyBindings[ i ].binding.parsedPath; + if ( this.isPlaying === true ) { - binding = new PropertyMixer( - PropertyBinding.create( root, trackName, path ), - track.ValueTypeName, track.getValueSize() ); + this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); - ++ binding.referenceCount; - this._addInactiveBinding( binding, rootUuid, trackName ); + } - bindings[ i ] = binding; + return this; - } + }, - interpolants[ i ].resultBuffer = binding.buffer; + getPlaybackRate: function () { - } + return this.playbackRate; }, - _activateAction: function ( action ) { + onEnded: function () { - if ( ! this._isActiveAction( action ) ) { + this.isPlaying = false; - if ( action._cacheIndex === null ) { + }, - // this action has been forgotten by the cache, but the user - // appears to be still using it -> rebind + getLoop: function () { - var rootUuid = ( action._localRoot || this._root ).uuid, - clipUuid = action._clip.uuid, - actionsForClip = this._actionsByClip[ clipUuid ]; + if ( this.hasPlaybackControl === false ) { - this._bindAction( action, - actionsForClip && actionsForClip.knownActions[ 0 ] ); + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return false; - this._addInactiveAction( action, clipUuid, rootUuid ); + } - } + return this.loop; - var bindings = action._propertyBindings; + }, - // increment reference counts / sort out state - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + setLoop: function ( value ) { - var binding = bindings[ i ]; + if ( this.hasPlaybackControl === false ) { - if ( binding.useCount ++ === 0 ) { + console.warn( 'THREE.Audio: this Audio has no playback control.' ); + return; - this._lendBinding( binding ); - binding.saveOriginalState(); + } - } + this.loop = value; - } + if ( this.isPlaying === true ) { - this._lendAction( action ); + this.source.loop = this.loop; } - }, + return this; - _deactivateAction: function ( action ) { + }, - if ( this._isActiveAction( action ) ) { + setLoopStart: function ( value ) { - var bindings = action._propertyBindings; + this.loopStart = value; - // decrement reference counts / sort out state - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + return this; - var binding = bindings[ i ]; + }, - if ( -- binding.useCount === 0 ) { + setLoopEnd: function ( value ) { - binding.restoreOriginalState(); - this._takeBackBinding( binding ); + this.loopEnd = value; - } + return this; - } + }, - this._takeBackAction( action ); + getVolume: function () { - } + return this.gain.gain.value; }, - // Memory manager - - _initMemoryManager: function () { + setVolume: function ( value ) { - this._actions = []; // 'nActiveActions' followed by inactive ones - this._nActiveActions = 0; + this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); - this._actionsByClip = {}; - // inside: - // { - // knownActions: Array< AnimationAction > - used as prototypes - // actionByRoot: AnimationAction - lookup - // } + return this; + } - this._bindings = []; // 'nActiveBindings' followed by inactive ones - this._nActiveBindings = 0; + } ); - this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > + var _position$3 = new Vector3(); + var _quaternion$4 = new Quaternion(); + var _scale$2 = new Vector3(); + var _orientation$1 = new Vector3(); + function PositionalAudio( listener ) { - this._controlInterpolants = []; // same game as above - this._nActiveControlInterpolants = 0; + Audio.call( this, listener ); - var scope = this; + this.panner = this.context.createPanner(); + this.panner.panningModel = 'HRTF'; + this.panner.connect( this.gain ); - this.stats = { + } - actions: { - get total() { + PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), { - return scope._actions.length; + constructor: PositionalAudio, - }, - get inUse() { + getOutput: function () { - return scope._nActiveActions; + return this.panner; - } - }, - bindings: { - get total() { + }, - return scope._bindings.length; + getRefDistance: function () { - }, - get inUse() { + return this.panner.refDistance; - return scope._nActiveBindings; + }, - } - }, - controlInterpolants: { - get total() { + setRefDistance: function ( value ) { - return scope._controlInterpolants.length; + this.panner.refDistance = value; - }, - get inUse() { + return this; - return scope._nActiveControlInterpolants; + }, - } - } + getRolloffFactor: function () { - }; + return this.panner.rolloffFactor; }, - // Memory management for AnimationAction objects + setRolloffFactor: function ( value ) { - _isActiveAction: function ( action ) { + this.panner.rolloffFactor = value; - var index = action._cacheIndex; - return index !== null && index < this._nActiveActions; + return this; }, - _addInactiveAction: function ( action, clipUuid, rootUuid ) { - - var actions = this._actions, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; + getDistanceModel: function () { - if ( actionsForClip === undefined ) { + return this.panner.distanceModel; - actionsForClip = { + }, - knownActions: [ action ], - actionByRoot: {} + setDistanceModel: function ( value ) { - }; + this.panner.distanceModel = value; - action._byClipCacheIndex = 0; + return this; - actionsByClip[ clipUuid ] = actionsForClip; + }, - } else { + getMaxDistance: function () { - var knownActions = actionsForClip.knownActions; + return this.panner.maxDistance; - action._byClipCacheIndex = knownActions.length; - knownActions.push( action ); + }, - } + setMaxDistance: function ( value ) { - action._cacheIndex = actions.length; - actions.push( action ); + this.panner.maxDistance = value; - actionsForClip.actionByRoot[ rootUuid ] = action; + return this; }, - _removeInactiveAction: function ( action ) { + setDirectionalCone: function ( coneInnerAngle, coneOuterAngle, coneOuterGain ) { - var actions = this._actions, - lastInactiveAction = actions[ actions.length - 1 ], - cacheIndex = action._cacheIndex; + this.panner.coneInnerAngle = coneInnerAngle; + this.panner.coneOuterAngle = coneOuterAngle; + this.panner.coneOuterGain = coneOuterGain; - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); + return this; - action._cacheIndex = null; + }, + updateMatrixWorld: function ( force ) { - var clipUuid = action._clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ], - knownActionsForClip = actionsForClip.knownActions, + Object3D.prototype.updateMatrixWorld.call( this, force ); - lastKnownAction = - knownActionsForClip[ knownActionsForClip.length - 1 ], + if ( this.hasPlaybackControl === true && this.isPlaying === false ) { return; } - byClipCacheIndex = action._byClipCacheIndex; + this.matrixWorld.decompose( _position$3, _quaternion$4, _scale$2 ); - lastKnownAction._byClipCacheIndex = byClipCacheIndex; - knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; - knownActionsForClip.pop(); + _orientation$1.set( 0, 0, 1 ).applyQuaternion( _quaternion$4 ); - action._byClipCacheIndex = null; + var panner = this.panner; + if ( panner.positionX ) { - var actionByRoot = actionsForClip.actionByRoot, - rootUuid = ( action._localRoot || this._root ).uuid; + // code path for Chrome and Firefox (see #14393) - delete actionByRoot[ rootUuid ]; + var endTime = this.context.currentTime + this.listener.timeDelta; - if ( knownActionsForClip.length === 0 ) { + panner.positionX.linearRampToValueAtTime( _position$3.x, endTime ); + panner.positionY.linearRampToValueAtTime( _position$3.y, endTime ); + panner.positionZ.linearRampToValueAtTime( _position$3.z, endTime ); + panner.orientationX.linearRampToValueAtTime( _orientation$1.x, endTime ); + panner.orientationY.linearRampToValueAtTime( _orientation$1.y, endTime ); + panner.orientationZ.linearRampToValueAtTime( _orientation$1.z, endTime ); - delete actionsByClip[ clipUuid ]; + } else { + + panner.setPosition( _position$3.x, _position$3.y, _position$3.z ); + panner.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z ); } - this._removeInactiveBindingsForAction( action ); + } - }, + } ); - _removeInactiveBindingsForAction: function ( action ) { + function AudioAnalyser( audio, fftSize ) { - var bindings = action._propertyBindings; - for ( var i = 0, n = bindings.length; i !== n; ++ i ) { + this.analyser = audio.context.createAnalyser(); + this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048; - var binding = bindings[ i ]; + this.data = new Uint8Array( this.analyser.frequencyBinCount ); - if ( -- binding.referenceCount === 0 ) { + audio.getOutput().connect( this.analyser ); - this._removeInactiveBinding( binding ); + } - } + Object.assign( AudioAnalyser.prototype, { - } + getFrequencyData: function () { - }, + this.analyser.getByteFrequencyData( this.data ); - _lendAction: function ( action ) { + return this.data; - // [ active actions | inactive actions ] - // [ active actions >| inactive actions ] - // s a - // <-swap-> - // a s + }, - var actions = this._actions, - prevIndex = action._cacheIndex, + getAverageFrequency: function () { - lastActiveIndex = this._nActiveActions ++, + var value = 0; + var data = this.getFrequencyData(); - firstInactiveAction = actions[ lastActiveIndex ]; + for ( var i = 0; i < data.length; i ++ ) { - action._cacheIndex = lastActiveIndex; - actions[ lastActiveIndex ] = action; + value += data[ i ]; - firstInactiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = firstInactiveAction; + } - }, + return value / data.length; - _takeBackAction: function ( action ) { + } - // [ active actions | inactive actions ] - // [ active actions |< inactive actions ] - // a s - // <-swap-> - // s a + } ); - var actions = this._actions, - prevIndex = action._cacheIndex, + function PropertyMixer( binding, typeName, valueSize ) { - firstInactiveIndex = -- this._nActiveActions, + this.binding = binding; + this.valueSize = valueSize; - lastActiveAction = actions[ firstInactiveIndex ]; + var mixFunction, + mixFunctionAdditive, + setIdentity; - action._cacheIndex = firstInactiveIndex; - actions[ firstInactiveIndex ] = action; + // 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 - lastActiveAction._cacheIndex = prevIndex; - actions[ prevIndex ] = lastActiveAction; + switch ( typeName ) { - }, + case 'quaternion': + mixFunction = this._slerp; + mixFunctionAdditive = this._slerpAdditive; + setIdentity = this._setAdditiveIdentityQuaternion; - // Memory management for PropertyMixer objects + this.buffer = new Float64Array( valueSize * 6 ); + this._workIndex = 5; + break; - _addInactiveBinding: function ( binding, rootUuid, trackName ) { + case 'string': + case 'bool': + mixFunction = this._select; - var bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ], + // Use the regular mix function and for additive on these types, + // additive is not relevant for non-numeric types + mixFunctionAdditive = this._select; - bindings = this._bindings; + setIdentity = this._setAdditiveIdentityOther; - if ( bindingByName === undefined ) { + this.buffer = new Array( valueSize * 5 ); + break; - bindingByName = {}; - bindingsByRoot[ rootUuid ] = bindingByName; + default: + mixFunction = this._lerp; + mixFunctionAdditive = this._lerpAdditive; + setIdentity = this._setAdditiveIdentityNumeric; - } + this.buffer = new Float64Array( valueSize * 5 ); - bindingByName[ trackName ] = binding; + } - binding._cacheIndex = bindings.length; - bindings.push( binding ); + this._mixBufferRegion = mixFunction; + this._mixBufferRegionAdditive = mixFunctionAdditive; + this._setIdentity = setIdentity; + this._origIndex = 3; + this._addIndex = 4; - }, + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; - _removeInactiveBinding: function ( binding ) { + this.useCount = 0; + this.referenceCount = 0; - var 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; + Object.assign( PropertyMixer.prototype, { - lastInactiveBinding._cacheIndex = cacheIndex; - bindings[ cacheIndex ] = lastInactiveBinding; - bindings.pop(); + // accumulate data in the 'incoming' region into 'accu' + accumulate: function ( accuIndex, weight ) { - delete bindingByName[ trackName ]; + // note: happily accumulating nothing when weight = 0, the caller knows + // the weight and shouldn't have made the call in the first place - remove_empty_map: { + var buffer = this.buffer, + stride = this.valueSize, + offset = accuIndex * stride + stride; - for ( var _ in bindingByName ) break remove_empty_map; // eslint-disable-line no-unused-vars + var currentWeight = this.cumulativeWeight; - delete bindingsByRoot[ rootUuid ]; + if ( currentWeight === 0 ) { - } + // accuN := incoming * weight - }, + for ( var i = 0; i !== stride; ++ i ) { - _lendBinding: function ( binding ) { + buffer[ offset + i ] = buffer[ i ]; - var bindings = this._bindings, - prevIndex = binding._cacheIndex, + } - lastActiveIndex = this._nActiveBindings ++, + currentWeight = weight; - firstInactiveBinding = bindings[ lastActiveIndex ]; + } else { - binding._cacheIndex = lastActiveIndex; - bindings[ lastActiveIndex ] = binding; + // accuN := accuN + incoming * weight - firstInactiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = firstInactiveBinding; + currentWeight += weight; + var mix = weight / currentWeight; + this._mixBufferRegion( buffer, offset, 0, mix, stride ); + + } + + this.cumulativeWeight = currentWeight; }, - _takeBackBinding: function ( binding ) { + // accumulate data in the 'incoming' region into 'add' + accumulateAdditive: function ( weight ) { - var bindings = this._bindings, - prevIndex = binding._cacheIndex, + var buffer = this.buffer, + stride = this.valueSize, + offset = stride * this._addIndex; - firstInactiveIndex = -- this._nActiveBindings, + if ( this.cumulativeWeightAdditive === 0 ) { - lastActiveBinding = bindings[ firstInactiveIndex ]; + // add = identity - binding._cacheIndex = firstInactiveIndex; - bindings[ firstInactiveIndex ] = binding; + this._setIdentity(); - lastActiveBinding._cacheIndex = prevIndex; - bindings[ prevIndex ] = lastActiveBinding; + } - }, + // add := add + incoming * weight + this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); + this.cumulativeWeightAdditive += weight; - // Memory management of Interpolants for weight and time scale + }, - _lendControlInterpolant: function () { + // apply the state of 'accu' to the binding when accus differ + apply: function ( accuIndex ) { - var interpolants = this._controlInterpolants, - lastActiveIndex = this._nActiveControlInterpolants ++, - interpolant = interpolants[ lastActiveIndex ]; + var stride = this.valueSize, + buffer = this.buffer, + offset = accuIndex * stride + stride, - if ( interpolant === undefined ) { + weight = this.cumulativeWeight, + weightAdditive = this.cumulativeWeightAdditive, - interpolant = new LinearInterpolant( - new Float32Array( 2 ), new Float32Array( 2 ), - 1, this._controlInterpolantsResultBuffer ); + binding = this.binding; - interpolant.__cacheIndex = lastActiveIndex; - interpolants[ lastActiveIndex ] = interpolant; + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; - } + if ( weight < 1 ) { - return interpolant; + // accuN := accuN + original * ( 1 - cumulativeWeight ) - }, + var originalValueOffset = stride * this._origIndex; - _takeBackControlInterpolant: function ( interpolant ) { + this._mixBufferRegion( + buffer, offset, originalValueOffset, 1 - weight, stride ); - var interpolants = this._controlInterpolants, - prevIndex = interpolant.__cacheIndex, + } - firstInactiveIndex = -- this._nActiveControlInterpolants, + if ( weightAdditive > 0 ) { - lastActiveInterpolant = interpolants[ firstInactiveIndex ]; + // accuN := accuN + additive accuN - interpolant.__cacheIndex = firstInactiveIndex; - interpolants[ firstInactiveIndex ] = interpolant; + this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); - lastActiveInterpolant.__cacheIndex = prevIndex; - interpolants[ prevIndex ] = lastActiveInterpolant; + } - }, + for ( var i = stride, e = stride + stride; i !== e; ++ i ) { - _controlInterpolantsResultBuffer: new Float32Array( 1 ), + if ( buffer[ i ] !== buffer[ i + stride ] ) { - // 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: function ( clip, optionalRoot ) { + // value has changed -> update scene graph - var root = optionalRoot || this._root, - rootUuid = root.uuid, + binding.setValue( buffer, offset ); + break; - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, + } - clipUuid = clipObject !== null ? clipObject.uuid : clip, + } - actionsForClip = this._actionsByClip[ clipUuid ], - prototypeAction = null; + }, - if ( actionsForClip !== undefined ) { + // remember the state of the bound property and copy it to both accus + saveOriginalState: function () { - var existingAction = - actionsForClip.actionByRoot[ rootUuid ]; + var binding = this.binding; - if ( existingAction !== undefined ) { + var buffer = this.buffer, + stride = this.valueSize, - return existingAction; + originalValueOffset = stride * this._origIndex; - } + binding.getValue( buffer, originalValueOffset ); - // we know the clip, so we don't have to parse all - // the bindings again but can just copy - prototypeAction = actionsForClip.knownActions[ 0 ]; + // accu[0..1] := orig -- initially detect changes against the original + for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) { - // also, take the clip from the prototype action - if ( clipObject === null ) - clipObject = prototypeAction._clip; + buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; } - // clip must be known when specified via string - if ( clipObject === null ) return null; + // Add to identity for additive + this._setIdentity(); - // allocate all resources required to run it - var newAction = new AnimationAction( this, clipObject, optionalRoot ); + this.cumulativeWeight = 0; + this.cumulativeWeightAdditive = 0; - this._bindAction( newAction, prototypeAction ); + }, - // and make the action known to the memory manager - this._addInactiveAction( newAction, clipUuid, rootUuid ); + // apply the state previously taken via 'saveOriginalState' to the binding + restoreOriginalState: function () { - return newAction; + var originalValueOffset = this.valueSize * 3; + this.binding.setValue( this.buffer, originalValueOffset ); }, - // get an existing action - existingAction: function ( clip, optionalRoot ) { - - var root = optionalRoot || this._root, - rootUuid = root.uuid, + _setAdditiveIdentityNumeric: function () { - clipObject = typeof clip === 'string' ? - AnimationClip.findByName( root, clip ) : clip, + var startIndex = this._addIndex * this.valueSize; + var endIndex = startIndex + this.valueSize; - clipUuid = clipObject ? clipObject.uuid : clip, + for ( var i = startIndex; i < endIndex; i ++ ) { - actionsForClip = this._actionsByClip[ clipUuid ]; + this.buffer[ i ] = 0; - if ( actionsForClip !== undefined ) { + } - return actionsForClip.actionByRoot[ rootUuid ] || null; + }, - } + _setAdditiveIdentityQuaternion: function () { - return null; + this._setAdditiveIdentityNumeric(); + this.buffer[ this._addIndex * 4 + 3 ] = 1; }, - // deactivates all previously scheduled actions - stopAllAction: function () { - - var actions = this._actions, - nActions = this._nActiveActions, - bindings = this._bindings, - nBindings = this._nActiveBindings; + _setAdditiveIdentityOther: function () { - this._nActiveActions = 0; - this._nActiveBindings = 0; + var startIndex = this._origIndex * this.valueSize; + var targetIndex = this._addIndex * this.valueSize; - for ( var i = 0; i !== nActions; ++ i ) { + for ( var i = 0; i < this.valueSize; i ++ ) { - actions[ i ].reset(); + this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; } - for ( var i = 0; i !== nBindings; ++ i ) { + }, - bindings[ i ].useCount = 0; - } + // mix functions - return this; + _select: function ( buffer, dstOffset, srcOffset, t, stride ) { - }, + if ( t >= 0.5 ) { - // advance the time and update apply the animation - update: function ( deltaTime ) { + for ( var i = 0; i !== stride; ++ i ) { - deltaTime *= this.timeScale; + buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; - var actions = this._actions, - nActions = this._nActiveActions, + } - time = this.time += deltaTime, - timeDirection = Math.sign( deltaTime ), + } - accuIndex = this._accuIndex ^= 1; + }, - // run active actions + _slerp: function ( buffer, dstOffset, srcOffset, t ) { - for ( var i = 0; i !== nActions; ++ i ) { + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); - var action = actions[ i ]; + }, - action._update( time, deltaTime, timeDirection, accuIndex ); + _slerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) { - } + var workOffset = this._workIndex * stride; - // update scene graph + // Store result in intermediate buffer offset + Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); - var bindings = this._bindings, - nBindings = this._nActiveBindings; + // Slerp to the intermediate result + Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); - for ( var i = 0; i !== nBindings; ++ i ) { + }, - bindings[ i ].apply( accuIndex ); + _lerp: function ( buffer, dstOffset, srcOffset, t, stride ) { - } + var s = 1 - t; - return this; + for ( var i = 0; i !== stride; ++ i ) { - }, + var j = dstOffset + i; - // return this mixer's root target object - getRoot: function () { + buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; - return this._root; + } }, - // free all resources specific to a particular clip - uncacheClip: function ( clip ) { + _lerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) { - var actions = this._actions, - clipUuid = clip.uuid, - actionsByClip = this._actionsByClip, - actionsForClip = actionsByClip[ clipUuid ]; + for ( var i = 0; i !== stride; ++ i ) { - if ( actionsForClip !== undefined ) { + var j = dstOffset + i; - // note: just calling _removeInactiveAction would mess up the - // iteration state and also require updating the state we can - // just throw away + buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; - var actionsToRemove = actionsForClip.knownActions; + } - for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { + } - var action = actionsToRemove[ i ]; + } ); - this._deactivateAction( action ); + // Characters [].:/ are reserved for track binding syntax. + var _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; + var _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); - var cacheIndex = action._cacheIndex, - lastInactiveAction = actions[ actions.length - 1 ]; + // 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. + var _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; + var _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; - action._cacheIndex = null; - action._byClipCacheIndex = null; + // Parent directories, delimited by '/' or ':'. Currently unused, but must + // be matched to parse the rest of the track name. + var _directoryRe = /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); - lastInactiveAction._cacheIndex = cacheIndex; - actions[ cacheIndex ] = lastInactiveAction; - actions.pop(); + // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. + var _nodeRe = /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); - this._removeInactiveBindingsForAction( action ); + // Object on target node, and accessor. May not contain reserved + // characters. Accessor may contain any character except closing bracket. + var _objectRe = /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); - } + // Property and accessor. May not contain reserved characters. Accessor may + // contain any non-bracket characters. + var _propertyRe = /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); - delete actionsByClip[ clipUuid ]; + var _trackRe = new RegExp( '' + + '^' + + _directoryRe + + _nodeRe + + _objectRe + + _propertyRe + + '$' + ); - } + var _supportedObjectNames = [ 'material', 'materials', 'bones' ]; - }, + function Composite( targetGroup, path, optionalParsedPath ) { - // free all resources specific to a particular root target object - uncacheRoot: function ( root ) { + var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); - var rootUuid = root.uuid, - actionsByClip = this._actionsByClip; + this._targetGroup = targetGroup; + this._bindings = targetGroup.subscribe_( path, parsedPath ); - for ( var clipUuid in actionsByClip ) { + } - var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, - action = actionByRoot[ rootUuid ]; + Object.assign( Composite.prototype, { - if ( action !== undefined ) { + getValue: function ( array, offset ) { - this._deactivateAction( action ); - this._removeInactiveAction( action ); + this.bind(); // bind all binding - } + var firstValidIndex = this._targetGroup.nCachedObjects_, + binding = this._bindings[ firstValidIndex ]; - } + // and only call .getValue on the first + if ( binding !== undefined ) { binding.getValue( array, offset ); } - var bindingsByRoot = this._bindingsByRootAndName, - bindingByName = bindingsByRoot[ rootUuid ]; + }, - if ( bindingByName !== undefined ) { + setValue: function ( array, offset ) { - for ( var trackName in bindingByName ) { + var bindings = this._bindings; - var binding = bindingByName[ trackName ]; - binding.restoreOriginalState(); - this._removeInactiveBinding( binding ); + for ( var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - } + bindings[ i ].setValue( array, offset ); } }, - // remove a targeted clip from the cache - uncacheAction: function ( clip, optionalRoot ) { + bind: function () { - var action = this.existingAction( clip, optionalRoot ); + var bindings = this._bindings; - if ( action !== null ) { + for ( var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - this._deactivateAction( action ); - this._removeInactiveAction( action ); + bindings[ i ].bind(); } - } + }, - } ); + unbind: function () { - /** - * @author mrdoob / http://mrdoob.com/ - */ + var bindings = this._bindings; - function Uniform( value ) { + for ( var i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { - if ( typeof value === 'string' ) { + bindings[ i ].unbind(); - console.warn( 'THREE.Uniform: Type parameter is no longer needed.' ); - value = arguments[ 1 ]; + } } - this.value = value; + } ); - } - Uniform.prototype.clone = function () { + function PropertyBinding( rootNode, path, parsedPath ) { - return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); + this.path = path; + this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); - }; + this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode; - /** - * @author benaadams / https://twitter.com/ben_a_adams - */ + this.rootNode = rootNode; - function InstancedBufferGeometry() { + } - BufferGeometry.call( this ); + Object.assign( PropertyBinding, { - this.type = 'InstancedBufferGeometry'; - this.maxInstancedCount = undefined; + Composite: Composite, - } + create: function ( root, path, parsedPath ) { - InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), { + if ( ! ( root && root.isAnimationObjectGroup ) ) { - constructor: InstancedBufferGeometry, + return new PropertyBinding( root, path, parsedPath ); - isInstancedBufferGeometry: true, + } else { - copy: function ( source ) { + return new PropertyBinding.Composite( root, path, parsedPath ); - BufferGeometry.prototype.copy.call( this, source ); + } - this.maxInstancedCount = source.maxInstancedCount; + }, - return this; + /** + * 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} + */ + sanitizeNodeName: function ( name ) { - }, + return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); - clone: function () { + }, - return new this.constructor().copy( this ); + parseTrackName: function ( trackName ) { - } + var matches = _trackRe.exec( trackName ); - } ); + if ( ! matches ) { - /** - * @author benaadams / https://twitter.com/ben_a_adams - */ + throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); - function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) { + } - InterleavedBuffer.call( this, array, stride ); + var results = { + // directoryName: matches[ 1 ], // (tschw) currently unused + nodeName: matches[ 2 ], + objectName: matches[ 3 ], + objectIndex: matches[ 4 ], + propertyName: matches[ 5 ], // required + propertyIndex: matches[ 6 ] + }; - this.meshPerAttribute = meshPerAttribute || 1; + var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); - } + if ( lastDot !== undefined && lastDot !== - 1 ) { - InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), { + var objectName = results.nodeName.substring( lastDot + 1 ); - constructor: InstancedInterleavedBuffer, + // 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 ) { - isInstancedInterleavedBuffer: true, + results.nodeName = results.nodeName.substring( 0, lastDot ); + results.objectName = objectName; - copy: function ( source ) { + } - InterleavedBuffer.prototype.copy.call( this, source ); + } - this.meshPerAttribute = source.meshPerAttribute; + if ( results.propertyName === null || results.propertyName.length === 0 ) { - return this; + throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); - } + } - } ); + return results; - /** - * @author benaadams / https://twitter.com/ben_a_adams - */ + }, - function InstancedBufferAttribute( array, itemSize, normalized, meshPerAttribute ) { + findNode: function ( root, nodeName ) { - if ( typeof ( normalized ) === 'number' ) { + if ( ! nodeName || nodeName === "" || nodeName === "." || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { - meshPerAttribute = normalized; + return root; - normalized = false; + } - console.error( 'THREE.InstancedBufferAttribute: The constructor now expects normalized as the third argument.' ); + // search into skeleton bones. + if ( root.skeleton ) { - } + var bone = root.skeleton.getBoneByName( nodeName ); - BufferAttribute.call( this, array, itemSize, normalized ); + if ( bone !== undefined ) { - this.meshPerAttribute = meshPerAttribute || 1; + return bone; - } + } - InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), { + } - constructor: InstancedBufferAttribute, + // search into node subtree. + if ( root.children ) { - isInstancedBufferAttribute: true, + var searchNodeSubtree = function ( children ) { - copy: function ( source ) { + for ( var i = 0; i < children.length; i ++ ) { - BufferAttribute.prototype.copy.call( this, source ); + var childNode = children[ i ]; - this.meshPerAttribute = source.meshPerAttribute; + if ( childNode.name === nodeName || childNode.uuid === nodeName ) { - return this; + return childNode; - } + } - } ); + var result = searchNodeSubtree( childNode.children ); - /** - * @author mrdoob / http://mrdoob.com/ - * @author bhouston / http://clara.io/ - * @author stephomi / http://stephaneginier.com/ - */ + if ( result ) { return result; } - function Raycaster( origin, direction, near, far ) { + } - this.ray = new Ray( origin, direction ); - // direction is assumed to be normalized (for accurate distance calculations) + return null; - this.near = near || 0; - this.far = far || Infinity; + }; - this.params = { - Mesh: {}, - Line: {}, - LOD: {}, - Points: { threshold: 1 }, - Sprite: {} - }; + var subTreeNode = searchNodeSubtree( root.children ); - Object.defineProperties( this.params, { - PointCloud: { - get: function () { + if ( subTreeNode ) { - console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); - return this.Points; + return subTreeNode; } + } - } ); - } + return null; - function ascSort( a, b ) { + } - return a.distance - b.distance; + } ); - } + Object.assign( PropertyBinding.prototype, { // prototype, continued - function intersectObject( object, raycaster, intersects, recursive ) { + // these are used to "bind" a nonexistent property + _getValue_unavailable: function () {}, + _setValue_unavailable: function () {}, - if ( object.visible === false ) return; + BindingType: { + Direct: 0, + EntireArray: 1, + ArrayElement: 2, + HasFromToArray: 3 + }, - object.raycast( raycaster, intersects ); + Versioning: { + None: 0, + NeedsUpdate: 1, + MatrixWorldNeedsUpdate: 2 + }, - if ( recursive === true ) { + GetterByBindingType: [ - var children = object.children; + function getValue_direct( buffer, offset ) { - for ( var i = 0, l = children.length; i < l; i ++ ) { + buffer[ offset ] = this.node[ this.propertyName ]; - intersectObject( children[ i ], raycaster, intersects, true ); + }, - } + function getValue_array( buffer, offset ) { - } + var source = this.resolvedProperty; - } + for ( var i = 0, n = source.length; i !== n; ++ i ) { - Object.assign( Raycaster.prototype, { + buffer[ offset ++ ] = source[ i ]; - linePrecision: 1, + } - set: function ( origin, direction ) { + }, - // direction is assumed to be normalized (for accurate distance calculations) + function getValue_arrayElement( buffer, offset ) { - this.ray.set( origin, direction ); + buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; - }, + }, - setFromCamera: function ( coords, camera ) { + function getValue_toArray( buffer, offset ) { - if ( ( camera && camera.isPerspectiveCamera ) ) { + this.resolvedProperty.toArray( buffer, offset ); - this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); - this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); + } - } 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 ); + SetterByBindingTypeAndVersioning: [ - } else { + [ + // Direct - console.error( 'THREE.Raycaster: Unsupported camera type.' ); + function setValue_direct( buffer, offset ) { - } + this.targetObject[ this.propertyName ] = buffer[ offset ]; - }, + }, - intersectObject: function ( object, recursive, optionalTarget ) { + function setValue_direct_setNeedsUpdate( buffer, offset ) { - var intersects = optionalTarget || []; + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; - intersectObject( object, this, intersects, recursive ); + }, - intersects.sort( ascSort ); + function setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { - return intersects; + this.targetObject[ this.propertyName ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; - }, + } - intersectObjects: function ( objects, recursive, optionalTarget ) { + ], [ - var intersects = optionalTarget || []; + // EntireArray - if ( Array.isArray( objects ) === false ) { + function setValue_array( buffer, offset ) { - console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); - return intersects; + var dest = this.resolvedProperty; - } + for ( var i = 0, n = dest.length; i !== n; ++ i ) { - for ( var i = 0, l = objects.length; i < l; i ++ ) { + dest[ i ] = buffer[ offset ++ ]; - intersectObject( objects[ i ], this, intersects, recursive ); + } - } + }, - intersects.sort( ascSort ); + function setValue_array_setNeedsUpdate( buffer, offset ) { - return intersects; + var dest = this.resolvedProperty; - } + for ( var i = 0, n = dest.length; i !== n; ++ i ) { - } ); + dest[ i ] = buffer[ offset ++ ]; - /** - * @author bhouston / http://clara.io - * @author WestLangley / http://github.com/WestLangley - * - * 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-axiz. - */ + } - function Spherical( radius, phi, theta ) { + this.targetObject.needsUpdate = true; - this.radius = ( radius !== undefined ) ? radius : 1.0; - this.phi = ( phi !== undefined ) ? phi : 0; // polar angle - this.theta = ( theta !== undefined ) ? theta : 0; // azimuthal angle + }, - return this; + function setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { - } + var dest = this.resolvedProperty; - Object.assign( Spherical.prototype, { + for ( var i = 0, n = dest.length; i !== n; ++ i ) { - set: function ( radius, phi, theta ) { + dest[ i ] = buffer[ offset ++ ]; - this.radius = radius; - this.phi = phi; - this.theta = theta; + } - return this; + this.targetObject.matrixWorldNeedsUpdate = true; - }, + } - clone: function () { + ], [ - return new this.constructor().copy( this ); + // ArrayElement - }, + function setValue_arrayElement( buffer, offset ) { - copy: function ( other ) { + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; - this.radius = other.radius; - this.phi = other.phi; - this.theta = other.theta; + }, - return this; + function setValue_arrayElement_setNeedsUpdate( buffer, offset ) { - }, + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.needsUpdate = true; - // restrict phi to be betwee EPS and PI-EPS - makeSafe: function () { + }, - var EPS = 0.000001; - this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); + function setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { - return this; + this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; + this.targetObject.matrixWorldNeedsUpdate = true; - }, + } - setFromVector3: function ( v ) { + ], [ - return this.setFromCartesianCoords( v.x, v.y, v.z ); + // HasToFromArray - }, + function setValue_fromArray( buffer, offset ) { - setFromCartesianCoords: function ( x, y, z ) { + this.resolvedProperty.fromArray( buffer, offset ); - this.radius = Math.sqrt( x * x + y * y + z * z ); + }, - if ( this.radius === 0 ) { + function setValue_fromArray_setNeedsUpdate( buffer, offset ) { - this.theta = 0; - this.phi = 0; + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.needsUpdate = true; - } else { + }, - this.theta = Math.atan2( x, z ); - this.phi = Math.acos( _Math.clamp( y / this.radius, - 1, 1 ) ); + function setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { - } + this.resolvedProperty.fromArray( buffer, offset ); + this.targetObject.matrixWorldNeedsUpdate = true; - return this; + } - } + ] - } ); + ], - /** - * @author Mugen87 / https://github.com/Mugen87 - * - * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system - * - */ + getValue: function getValue_unbound( targetArray, offset ) { - function Cylindrical( radius, theta, y ) { + this.bind(); + this.getValue( targetArray, offset ); - this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane - this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis - this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane + // 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. - return this; + }, - } + setValue: function getValue_unbound( sourceArray, offset ) { - Object.assign( Cylindrical.prototype, { + this.bind(); + this.setValue( sourceArray, offset ); - set: function ( radius, theta, y ) { + }, - this.radius = radius; - this.theta = theta; - this.y = y; + // create getter / setter pair for a property in the scene graph + bind: function () { - return this; + var targetObject = this.node, + parsedPath = this.parsedPath, - }, + objectName = parsedPath.objectName, + propertyName = parsedPath.propertyName, + propertyIndex = parsedPath.propertyIndex; - clone: function () { + if ( ! targetObject ) { - return new this.constructor().copy( this ); + targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ) || this.rootNode; - }, + this.node = targetObject; - copy: function ( other ) { + } - this.radius = other.radius; - this.theta = other.theta; - this.y = other.y; + // set fail state so we can just 'return' on error + this.getValue = this._getValue_unavailable; + this.setValue = this._setValue_unavailable; - return this; + // 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; - setFromVector3: function ( v ) { + } - return this.setFromCartesianCoords( v.x, v.y, v.z ); + if ( objectName ) { - }, + var objectIndex = parsedPath.objectIndex; - setFromCartesianCoords: function ( x, y, z ) { + // special cases were we need to reach deeper into the hierarchy to get the face materials.... + switch ( objectName ) { - this.radius = Math.sqrt( x * x + z * z ); - this.theta = Math.atan2( x, z ); - this.y = y; + case 'materials': - return this; + if ( ! targetObject.material ) { - } + console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); + return; - } ); + } - /** - * @author bhouston / http://clara.io - */ + if ( ! targetObject.material.materials ) { - function Box2( min, max ) { + console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); + return; - this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity ); - this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity ); + } - } + targetObject = targetObject.material.materials; - Object.assign( Box2.prototype, { + break; - set: function ( min, max ) { + case 'bones': - this.min.copy( min ); - this.max.copy( max ); + if ( ! targetObject.skeleton ) { - return this; + console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); + return; - }, + } - setFromPoints: function ( points ) { + // potential future optimization: skip this if propertyIndex is already an integer + // and convert the integer string to a true integer. - this.makeEmpty(); + targetObject = targetObject.skeleton.bones; - for ( var i = 0, il = points.length; i < il; i ++ ) { + // support resolving morphTarget names into indices. + for ( var i = 0; i < targetObject.length; i ++ ) { - this.expandByPoint( points[ i ] ); + if ( targetObject[ i ].name === objectIndex ) { - } + objectIndex = i; + break; - return this; + } - }, + } - setFromCenterAndSize: function () { + break; - var v1 = new Vector2(); + default: - return function setFromCenterAndSize( center, size ) { + if ( targetObject[ objectName ] === undefined ) { - var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); + return; - return this; + } - }; + targetObject = targetObject[ objectName ]; - }(), + } - clone: function () { - return new this.constructor().copy( this ); + if ( objectIndex !== undefined ) { - }, + if ( targetObject[ objectIndex ] === undefined ) { - copy: function ( box ) { + console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); + return; - this.min.copy( box.min ); - this.max.copy( box.max ); + } - return this; + targetObject = targetObject[ objectIndex ]; - }, + } - makeEmpty: function () { + } - this.min.x = this.min.y = + Infinity; - this.max.x = this.max.y = - Infinity; + // resolve property + var nodeProperty = targetObject[ propertyName ]; - return this; + if ( nodeProperty === undefined ) { - }, + var nodeName = parsedPath.nodeName; - isEmpty: function () { + console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + + '.' + propertyName + ' but it wasn\'t found.', targetObject ); + return; - // 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 ); + // determine versioning scheme + var versioning = this.Versioning.None; - }, + this.targetObject = targetObject; - getCenter: function ( target ) { + if ( targetObject.needsUpdate !== undefined ) { // material - if ( target === undefined ) { + versioning = this.Versioning.NeedsUpdate; - console.warn( 'THREE.Box2: .getCenter() target is now required' ); - target = new Vector2(); + } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform + + versioning = this.Versioning.MatrixWorldNeedsUpdate; } - return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + // determine how the property gets bound + var bindingType = this.BindingType.Direct; - }, + if ( propertyIndex !== undefined ) { - getSize: function ( target ) { + // access a sub element of the property array (only primitives are supported right now) - if ( target === undefined ) { + if ( propertyName === "morphTargetInfluences" ) { - console.warn( 'THREE.Box2: .getSize() target is now required' ); - target = new Vector2(); + // 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 ) { - return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); + return; - }, + } - expandByPoint: function ( point ) { + if ( targetObject.geometry.isBufferGeometry ) { - this.min.min( point ); - this.max.max( point ); + if ( ! targetObject.geometry.morphAttributes ) { - return this; + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); + return; - }, + } - expandByVector: function ( vector ) { + if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { - this.min.sub( vector ); - this.max.add( vector ); + propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; - return this; + } - }, - expandByScalar: function ( scalar ) { + } else { - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences on THREE.Geometry. Use THREE.BufferGeometry instead.', this ); + return; - return this; + } - }, + } - containsPoint: function ( point ) { + bindingType = this.BindingType.ArrayElement; - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y ? false : true; + this.resolvedProperty = nodeProperty; + this.propertyIndex = propertyIndex; - }, + } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { - containsBox: function ( box ) { + // must use copy for Object3D.Euler/Quaternion - 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; + bindingType = this.BindingType.HasFromToArray; - }, + this.resolvedProperty = nodeProperty; - getParameter: function ( point, target ) { + } else if ( Array.isArray( nodeProperty ) ) { - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + bindingType = this.BindingType.EntireArray; - if ( target === undefined ) { + this.resolvedProperty = nodeProperty; - console.warn( 'THREE.Box2: .getParameter() target is now required' ); - target = new Vector2(); + } else { + + this.propertyName = propertyName; } - 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 ) - ); + // select getter / setter + this.getValue = this.GetterByBindingType[ bindingType ]; + this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; }, - intersectsBox: function ( box ) { + unbind: function () { - // using 4 splitting planes to rule out intersections + this.node = null; - 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; + // 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; - }, + } - clampPoint: function ( point, target ) { + } ); - if ( target === undefined ) { + // DECLARE ALIAS AFTER assign prototype + Object.assign( PropertyBinding.prototype, { - console.warn( 'THREE.Box2: .clampPoint() target is now required' ); - target = new Vector2(); + // initial state of these methods that calls 'bind' + _getValue_unbound: PropertyBinding.prototype.getValue, + _setValue_unbound: PropertyBinding.prototype.setValue, - } + } ); - return target.copy( point ).clamp( this.min, this.max ); + /** + * + * 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. + */ - }, + function AnimationObjectGroup() { - distanceToPoint: function () { + this.uuid = MathUtils.generateUUID(); - var v1 = new Vector2(); + // cached objects followed by the active ones + this._objects = Array.prototype.slice.call( arguments ); - return function distanceToPoint( point ) { + this.nCachedObjects_ = 0; // threshold + // note: read by PropertyBinding.Composite - var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); - return clampedPoint.sub( point ).length(); + var indices = {}; + this._indicesByUUID = indices; // for bookkeeping - }; + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - }(), + indices[ arguments[ i ].uuid ] = i; - intersect: function ( box ) { + } - this.min.max( box.min ); - this.max.min( box.max ); + this._paths = []; // inside: string + this._parsedPaths = []; // inside: { we don't care, here } + this._bindings = []; // inside: Array< PropertyBinding > + this._bindingsIndicesByPath = {}; // inside: indices in these arrays - return this; + var scope = this; - }, + this.stats = { - union: function ( box ) { + objects: { + get total() { - this.min.min( box.min ); - this.max.max( box.max ); + return scope._objects.length; - return this; + }, + get inUse() { - }, + return this.total - scope.nCachedObjects_; - translate: function ( offset ) { + } + }, + get bindingsPerObject() { - this.min.add( offset ); - this.max.add( offset ); + return scope._bindings.length; - return this; + } - }, + }; - equals: function ( box ) { + } - return box.min.equals( this.min ) && box.max.equals( this.max ); + Object.assign( AnimationObjectGroup.prototype, { - } + isAnimationObjectGroup: true, - } ); + add: function () { - /** - * @author bhouston / http://clara.io - */ + var objects = this._objects, + indicesByUUID = this._indicesByUUID, + paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + nBindings = bindings.length; - function Line3( start, end ) { + var knownObject = undefined, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_; - this.start = ( start !== undefined ) ? start : new Vector3(); - this.end = ( end !== undefined ) ? end : new Vector3(); + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - } + var object = arguments[ i ], + uuid = object.uuid; + var index = indicesByUUID[ uuid ]; - Object.assign( Line3.prototype, { + if ( index === undefined ) { - set: function ( start, end ) { + // unknown object -> add it to the ACTIVE region - this.start.copy( start ); - this.end.copy( end ); + index = nObjects ++; + indicesByUUID[ uuid ] = index; + objects.push( object ); - return this; + // accounting is done, now do the same for all bindings - }, + for ( var j = 0, m = nBindings; j !== m; ++ j ) { - clone: function () { + bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); - return new this.constructor().copy( this ); + } - }, + } else if ( index < nCachedObjects ) { - copy: function ( line ) { + knownObject = objects[ index ]; - this.start.copy( line.start ); - this.end.copy( line.end ); + // move existing object to the ACTIVE region - return this; + var firstActiveIndex = -- nCachedObjects, + lastCachedObject = objects[ firstActiveIndex ]; - }, + indicesByUUID[ lastCachedObject.uuid ] = index; + objects[ index ] = lastCachedObject; - getCenter: function ( target ) { + indicesByUUID[ uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = object; - if ( target === undefined ) { + // accounting is done, now do the same for all bindings - console.warn( 'THREE.Line3: .getCenter() target is now required' ); - target = new Vector3(); + for ( var j$1 = 0, m$1 = nBindings; j$1 !== m$1; ++ j$1 ) { - } + var bindingsForPath = bindings[ j$1 ], + lastCached = bindingsForPath[ firstActiveIndex ]; - return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); + var binding = bindingsForPath[ index ]; - }, + bindingsForPath[ index ] = lastCached; - delta: function ( target ) { + if ( binding === undefined ) { - if ( target === undefined ) { + // since we do not bother to create new bindings + // for objects that are cached, the binding may + // or may not exist - console.warn( 'THREE.Line3: .delta() target is now required' ); - target = new Vector3(); + binding = new PropertyBinding( object, paths[ j$1 ], parsedPaths[ j$1 ] ); - } + } - return target.subVectors( this.end, this.start ); + bindingsForPath[ firstActiveIndex ] = binding; - }, + } - distanceSq: function () { + } else if ( objects[ index ] !== knownObject ) { - return this.start.distanceToSquared( this.end ); + 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 - distance: function () { + } // for arguments - return this.start.distanceTo( this.end ); + this.nCachedObjects_ = nCachedObjects; }, - at: function ( t, target ) { + remove: function () { - if ( target === undefined ) { + var objects = this._objects, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; - console.warn( 'THREE.Line3: .at() target is now required' ); - target = new Vector3(); + var nCachedObjects = this.nCachedObjects_; - } + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - return this.delta( target ).multiplyScalar( t ).add( this.start ); + var object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; - }, + if ( index !== undefined && index >= nCachedObjects ) { + + // move existing object into the CACHED region - closestPointToPointParameter: function () { + var lastCachedIndex = nCachedObjects ++, + firstActiveObject = objects[ lastCachedIndex ]; - var startP = new Vector3(); - var startEnd = new Vector3(); + indicesByUUID[ firstActiveObject.uuid ] = index; + objects[ index ] = firstActiveObject; - return function closestPointToPointParameter( point, clampToLine ) { + indicesByUUID[ uuid ] = lastCachedIndex; + objects[ lastCachedIndex ] = object; - startP.subVectors( point, this.start ); - startEnd.subVectors( this.end, this.start ); + // accounting is done, now do the same for all bindings - var startEnd2 = startEnd.dot( startEnd ); - var startEnd_startP = startEnd.dot( startP ); + for ( var j = 0, m = nBindings; j !== m; ++ j ) { - var t = startEnd_startP / startEnd2; + var bindingsForPath = bindings[ j ], + firstActive = bindingsForPath[ lastCachedIndex ], + binding = bindingsForPath[ index ]; - if ( clampToLine ) { + bindingsForPath[ index ] = firstActive; + bindingsForPath[ lastCachedIndex ] = binding; - t = _Math.clamp( t, 0, 1 ); + } } - return t; + } // for arguments - }; + this.nCachedObjects_ = nCachedObjects; - }(), + }, - closestPointToPoint: function ( point, clampToLine, target ) { + // remove & forget + uncache: function () { - var t = this.closestPointToPointParameter( point, clampToLine ); + var objects = this._objects, + indicesByUUID = this._indicesByUUID, + bindings = this._bindings, + nBindings = bindings.length; - if ( target === undefined ) { + var nCachedObjects = this.nCachedObjects_, + nObjects = objects.length; - console.warn( 'THREE.Line3: .closestPointToPoint() target is now required' ); - target = new Vector3(); + for ( var i = 0, n = arguments.length; i !== n; ++ i ) { - } + var object = arguments[ i ], + uuid = object.uuid, + index = indicesByUUID[ uuid ]; - return this.delta( target ).multiplyScalar( t ).add( this.start ); + if ( index !== undefined ) { - }, + delete indicesByUUID[ uuid ]; - applyMatrix4: function ( matrix ) { + if ( index < nCachedObjects ) { - this.start.applyMatrix4( matrix ); - this.end.applyMatrix4( matrix ); + // object is cached, shrink the CACHED region - return this; + var 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; - equals: function ( line ) { + // last object goes to the activated slot and pop + indicesByUUID[ lastObject.uuid ] = firstActiveIndex; + objects[ firstActiveIndex ] = lastObject; + objects.pop(); - return line.start.equals( this.start ) && line.end.equals( this.end ); + // accounting is done, now do the same for all bindings - } + for ( var j = 0, m = nBindings; j !== m; ++ j ) { - } ); + var bindingsForPath = bindings[ j ], + lastCached = bindingsForPath[ firstActiveIndex ], + last = bindingsForPath[ lastIndex ]; - /** - * @author alteredq / http://alteredqualia.com/ - */ + bindingsForPath[ index ] = lastCached; + bindingsForPath[ firstActiveIndex ] = last; + bindingsForPath.pop(); - function ImmediateRenderObject( material ) { + } - Object3D.call( this ); + } else { - this.material = material; - this.render = function ( /* renderCallback */ ) {}; + // object is active, just swap with the last and pop - } + var lastIndex$1 = -- nObjects, + lastObject$1 = objects[ lastIndex$1 ]; - ImmediateRenderObject.prototype = Object.create( Object3D.prototype ); - ImmediateRenderObject.prototype.constructor = ImmediateRenderObject; + indicesByUUID[ lastObject$1.uuid ] = index; + objects[ index ] = lastObject$1; + objects.pop(); - ImmediateRenderObject.prototype.isImmediateRenderObject = true; + // accounting is done, now do the same for all bindings - /** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ + for ( var j$1 = 0, m$1 = nBindings; j$1 !== m$1; ++ j$1 ) { - function VertexNormalsHelper( object, size, hex, linewidth ) { + var bindingsForPath$1 = bindings[ j$1 ]; - this.object = object; + bindingsForPath$1[ index ] = bindingsForPath$1[ lastIndex$1 ]; + bindingsForPath$1.pop(); - this.size = ( size !== undefined ) ? size : 1; + } - var color = ( hex !== undefined ) ? hex : 0xff0000; + } // cached or active - var width = ( linewidth !== undefined ) ? linewidth : 1; + } // if object is known - // + } // for arguments - var nNormals = 0; + this.nCachedObjects_ = nCachedObjects; - var objGeometry = this.object.geometry; + }, - if ( objGeometry && objGeometry.isGeometry ) { + // Internal interface used by befriended PropertyBinding.Composite: - nNormals = objGeometry.faces.length * 3; + subscribe_: function ( path, parsedPath ) { - } else if ( objGeometry && objGeometry.isBufferGeometry ) { + // returns an array of bindings for the given path that is changed + // according to the contained objects in the group - nNormals = objGeometry.attributes.normal.count; + var indicesByPath = this._bindingsIndicesByPath, + index = indicesByPath[ path ], + bindings = this._bindings; - } + if ( index !== undefined ) { return bindings[ index ]; } - // + var paths = this._paths, + parsedPaths = this._parsedPaths, + objects = this._objects, + nObjects = objects.length, + nCachedObjects = this.nCachedObjects_, + bindingsForPath = new Array( nObjects ); - var geometry = new BufferGeometry(); + index = bindings.length; - var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); + indicesByPath[ path ] = index; - geometry.addAttribute( 'position', positions ); + paths.push( path ); + parsedPaths.push( parsedPath ); + bindings.push( bindingsForPath ); - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); + for ( var i = nCachedObjects, n = objects.length; i !== n; ++ i ) { - // + var object = objects[ i ]; + bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); - this.matrixAutoUpdate = false; + } - this.update(); + return bindingsForPath; - } + }, - VertexNormalsHelper.prototype = Object.create( LineSegments.prototype ); - VertexNormalsHelper.prototype.constructor = VertexNormalsHelper; + unsubscribe_: function ( path ) { - VertexNormalsHelper.prototype.update = ( function () { + // tells the group to forget about a property path and no longer + // update the array previously obtained with 'subscribe_' - var v1 = new Vector3(); - var v2 = new Vector3(); - var normalMatrix = new Matrix3(); + var indicesByPath = this._bindingsIndicesByPath, + index = indicesByPath[ path ]; - return function update() { + if ( index !== undefined ) { - var keys = [ 'a', 'b', 'c' ]; + var paths = this._paths, + parsedPaths = this._parsedPaths, + bindings = this._bindings, + lastBindingsIndex = bindings.length - 1, + lastBindings = bindings[ lastBindingsIndex ], + lastBindingsPath = path[ lastBindingsIndex ]; - this.object.updateMatrixWorld( true ); + indicesByPath[ lastBindingsPath ] = index; - normalMatrix.getNormalMatrix( this.object.matrixWorld ); + bindings[ index ] = lastBindings; + bindings.pop(); - var matrixWorld = this.object.matrixWorld; + parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; + parsedPaths.pop(); - var position = this.geometry.attributes.position; + paths[ index ] = paths[ lastBindingsIndex ]; + paths.pop(); - // + } - var objGeometry = this.object.geometry; + } - if ( objGeometry && objGeometry.isGeometry ) { + } ); - var vertices = objGeometry.vertices; + function AnimationAction( mixer, clip, localRoot, blendMode ) { - var faces = objGeometry.faces; + this._mixer = mixer; + this._clip = clip; + this._localRoot = localRoot || null; + this.blendMode = blendMode || clip.blendMode; - var idx = 0; + var tracks = clip.tracks, + nTracks = tracks.length, + interpolants = new Array( nTracks ); - for ( var i = 0, l = faces.length; i < l; i ++ ) { + var interpolantSettings = { + endingStart: ZeroCurvatureEnding, + endingEnd: ZeroCurvatureEnding + }; - var face = faces[ i ]; + for ( var i = 0; i !== nTracks; ++ i ) { - for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { + var interpolant = tracks[ i ].createInterpolant( null ); + interpolants[ i ] = interpolant; + interpolant.settings = interpolantSettings; - var vertex = vertices[ face[ keys[ j ] ] ]; + } - var normal = face.vertexNormals[ j ]; + this._interpolantSettings = interpolantSettings; - v1.copy( vertex ).applyMatrix4( matrixWorld ); + this._interpolants = interpolants; // bound by the mixer - v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + // inside: PropertyMixer (managed by the mixer) + this._propertyBindings = new Array( nTracks ); - position.setXYZ( idx, v1.x, v1.y, v1.z ); + this._cacheIndex = null; // for the memory manager + this._byClipCacheIndex = null; // for the memory manager - idx = idx + 1; + this._timeScaleInterpolant = null; + this._weightInterpolant = null; - position.setXYZ( idx, v2.x, v2.y, v2.z ); + this.loop = LoopRepeat; + this._loopCount = - 1; - idx = idx + 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; - } else if ( objGeometry && objGeometry.isBufferGeometry ) { + this.weight = 1; + this._effectiveWeight = 1; - var objPos = objGeometry.attributes.position; + this.repetitions = Infinity; // no. of repetitions when looping - var objNorm = objGeometry.attributes.normal; + this.paused = false; // true -> zero effective time scale + this.enabled = true; // false -> zero effective weight - var idx = 0; + this.clampWhenFinished = false;// keep feeding the last frame? - // for simplicity, ignore index and drawcalls, and render every normal + this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate + this.zeroSlopeAtEnd = true;// clips for start, loop and end - for ( var j = 0, jl = objPos.count; j < jl; j ++ ) { + } - v1.set( objPos.getX( j ), objPos.getY( j ), objPos.getZ( j ) ).applyMatrix4( matrixWorld ); + Object.assign( AnimationAction.prototype, { - v2.set( objNorm.getX( j ), objNorm.getY( j ), objNorm.getZ( j ) ); + // State & Scheduling - v2.applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + play: function () { - position.setXYZ( idx, v1.x, v1.y, v1.z ); + this._mixer._activateAction( this ); - idx = idx + 1; + return this; - position.setXYZ( idx, v2.x, v2.y, v2.z ); + }, - idx = idx + 1; + stop: function () { - } + this._mixer._deactivateAction( this ); - } + return this.reset(); - position.needsUpdate = true; + }, - }; + reset: function () { - }() ); + this.paused = false; + this.enabled = true; - /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ + this.time = 0; // restart clip + this._loopCount = - 1;// forget previous loops + this._startTime = null;// forget scheduling - function SpotLightHelper( light, color ) { + return this.stopFading().stopWarping(); - Object3D.call( this ); + }, - this.light = light; - this.light.updateMatrixWorld(); + isRunning: function () { - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + return this.enabled && ! this.paused && this.timeScale !== 0 && + this._startTime === null && this._mixer._isActiveAction( this ); - this.color = color; + }, - var geometry = new BufferGeometry(); + // return true when play has been called + isScheduled: function () { - var 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 - ]; + return this._mixer._isActiveAction( this ); - for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { + }, - var p1 = ( i / l ) * Math.PI * 2; - var p2 = ( j / l ) * Math.PI * 2; + startAt: function ( time ) { - positions.push( - Math.cos( p1 ), Math.sin( p1 ), 1, - Math.cos( p2 ), Math.sin( p2 ), 1 - ); + this._startTime = time; - } + return this; - geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + }, - var material = new LineBasicMaterial( { fog: false } ); + setLoop: function ( mode, repetitions ) { - this.cone = new LineSegments( geometry, material ); - this.add( this.cone ); + this.loop = mode; + this.repetitions = repetitions; - this.update(); + return this; - } + }, - SpotLightHelper.prototype = Object.create( Object3D.prototype ); - SpotLightHelper.prototype.constructor = SpotLightHelper; + // Weight - SpotLightHelper.prototype.dispose = function () { + // 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: function ( weight ) { - this.cone.geometry.dispose(); - this.cone.material.dispose(); + this.weight = weight; - }; + // note: same logic as when updated at runtime + this._effectiveWeight = this.enabled ? weight : 0; - SpotLightHelper.prototype.update = function () { + return this.stopFading(); - var vector = new Vector3(); - var vector2 = new Vector3(); + }, - return function update() { + // return the weight considering fading and .enabled + getEffectiveWeight: function () { - this.light.updateMatrixWorld(); + return this._effectiveWeight; - var coneLength = this.light.distance ? this.light.distance : 1000; - var coneWidth = coneLength * Math.tan( this.light.angle ); + }, - this.cone.scale.set( coneWidth, coneWidth, coneLength ); + fadeIn: function ( duration ) { - vector.setFromMatrixPosition( this.light.matrixWorld ); - vector2.setFromMatrixPosition( this.light.target.matrixWorld ); + return this._scheduleFading( duration, 0, 1 ); - this.cone.lookAt( vector2.sub( vector ) ); + }, - if ( this.color !== undefined ) { + fadeOut: function ( duration ) { - this.cone.material.color.set( this.color ); + return this._scheduleFading( duration, 1, 0 ); - } else { + }, - this.cone.material.color.copy( this.light.color ); + crossFadeFrom: function ( fadeOutAction, duration, warp ) { - } + fadeOutAction.fadeOut( duration ); + this.fadeIn( duration ); - }; + if ( warp ) { - }(); + var fadeInDuration = this._clip.duration, + fadeOutDuration = fadeOutAction._clip.duration, - /** - * @author Sean Griffin / http://twitter.com/sgrif - * @author Michael Guerrero / http://realitymeltdown.com - * @author mrdoob / http://mrdoob.com/ - * @author ikerr / http://verold.com - * @author Mugen87 / https://github.com/Mugen87 - */ + startEndRatio = fadeOutDuration / fadeInDuration, + endStartRatio = fadeInDuration / fadeOutDuration; - function getBoneList( object ) { + fadeOutAction.warp( 1.0, startEndRatio, duration ); + this.warp( endStartRatio, 1.0, duration ); - var boneList = []; + } - if ( object && object.isBone ) { + return this; - boneList.push( object ); + }, - } + crossFadeTo: function ( fadeInAction, duration, warp ) { - for ( var i = 0; i < object.children.length; i ++ ) { + return fadeInAction.crossFadeFrom( this, duration, warp ); - boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); + }, - } + stopFading: function () { - return boneList; + var weightInterpolant = this._weightInterpolant; - } + if ( weightInterpolant !== null ) { - function SkeletonHelper( object ) { + this._weightInterpolant = null; + this._mixer._takeBackControlInterpolant( weightInterpolant ); - var bones = getBoneList( object ); + } - var geometry = new BufferGeometry(); + return this; - var vertices = []; - var colors = []; + }, - var color1 = new Color( 0, 0, 1 ); - var color2 = new Color( 0, 1, 0 ); + // Time Scale Control - for ( var i = 0; i < bones.length; i ++ ) { + // 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: function ( timeScale ) { - var bone = bones[ i ]; + this.timeScale = timeScale; + this._effectiveTimeScale = this.paused ? 0 : timeScale; - if ( bone.parent && bone.parent.isBone ) { + return this.stopWarping(); - 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 ); + }, - } + // return the time scale considering warping and .paused + getEffectiveTimeScale: function () { - } + return this._effectiveTimeScale; - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + }, - var material = new LineBasicMaterial( { vertexColors: VertexColors, depthTest: false, depthWrite: false, transparent: true } ); + setDuration: function ( duration ) { - LineSegments.call( this, geometry, material ); + this.timeScale = this._clip.duration / duration; - this.root = object; - this.bones = bones; + return this.stopWarping(); - this.matrix = object.matrixWorld; - this.matrixAutoUpdate = false; + }, - } + syncWith: function ( action ) { - SkeletonHelper.prototype = Object.create( LineSegments.prototype ); - SkeletonHelper.prototype.constructor = SkeletonHelper; + this.time = action.time; + this.timeScale = action.timeScale; - SkeletonHelper.prototype.updateMatrixWorld = function () { + return this.stopWarping(); - var vector = new Vector3(); + }, - var boneMatrix = new Matrix4(); - var matrixWorldInv = new Matrix4(); + halt: function ( duration ) { - return function updateMatrixWorld( force ) { + return this.warp( this._effectiveTimeScale, 0, duration ); - var bones = this.bones; + }, - var geometry = this.geometry; - var position = geometry.getAttribute( 'position' ); + warp: function ( startTimeScale, endTimeScale, duration ) { - matrixWorldInv.getInverse( this.root.matrixWorld ); + var mixer = this._mixer, + now = mixer.time, + timeScale = this.timeScale; - for ( var i = 0, j = 0; i < bones.length; i ++ ) { + var interpolant = this._timeScaleInterpolant; - var bone = bones[ i ]; + if ( interpolant === null ) { - if ( bone.parent && bone.parent.isBone ) { + interpolant = mixer._lendControlInterpolant(); + this._timeScaleInterpolant = interpolant; - boneMatrix.multiplyMatrices( matrixWorldInv, bone.matrixWorld ); - vector.setFromMatrixPosition( boneMatrix ); - position.setXYZ( j, vector.x, vector.y, vector.z ); + } - boneMatrix.multiplyMatrices( matrixWorldInv, bone.parent.matrixWorld ); - vector.setFromMatrixPosition( boneMatrix ); - position.setXYZ( j + 1, vector.x, vector.y, vector.z ); + var times = interpolant.parameterPositions, + values = interpolant.sampleValues; - j += 2; + times[ 0 ] = now; + times[ 1 ] = now + duration; - } + values[ 0 ] = startTimeScale / timeScale; + values[ 1 ] = endTimeScale / timeScale; - } + return this; - geometry.getAttribute( 'position' ).needsUpdate = true; + }, - Object3D.prototype.updateMatrixWorld.call( this, force ); + stopWarping: function () { - }; + var timeScaleInterpolant = this._timeScaleInterpolant; - }(); + if ( timeScaleInterpolant !== null ) { - /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - */ + this._timeScaleInterpolant = null; + this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); - function PointLightHelper( light, sphereSize, color ) { + } - this.light = light; - this.light.updateMatrixWorld(); + return this; - this.color = color; + }, - var geometry = new SphereBufferGeometry( sphereSize, 4, 2 ); - var material = new MeshBasicMaterial( { wireframe: true, fog: false } ); + // Object Accessors - Mesh.call( this, geometry, material ); + getMixer: function () { - this.matrix = this.light.matrixWorld; - this.matrixAutoUpdate = false; + return this._mixer; - this.update(); + }, + getClip: function () { - /* - var distanceGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 ); - var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); + return this._clip; - this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); - this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); + }, - var d = light.distance; + getRoot: function () { - if ( d === 0.0 ) { + return this._localRoot || this._mixer._root; - this.lightDistance.visible = false; + }, - } else { + // Interna - this.lightDistance.scale.set( d, d, d ); + _update: function ( time, deltaTime, timeDirection, accuIndex ) { - } + // called by the mixer - this.add( this.lightDistance ); - */ + if ( ! this.enabled ) { - } + // call ._updateWeight() to update ._effectiveWeight - PointLightHelper.prototype = Object.create( Mesh.prototype ); - PointLightHelper.prototype.constructor = PointLightHelper; + this._updateWeight( time ); + return; - PointLightHelper.prototype.dispose = function () { + } - this.geometry.dispose(); - this.material.dispose(); + var startTime = this._startTime; - }; + if ( startTime !== null ) { - PointLightHelper.prototype.update = function () { + // check for scheduled start of action - if ( this.color !== undefined ) { + var timeRunning = ( time - startTime ) * timeDirection; + if ( timeRunning < 0 || timeDirection === 0 ) { - this.material.color.set( this.color ); + return; // yet to come / don't decide when delta = 0 - } else { + } - this.material.color.copy( this.light.color ); + // start - } + this._startTime = null; // unschedule + deltaTime = timeDirection * timeRunning; - /* - var d = this.light.distance; + } - if ( d === 0.0 ) { + // apply time scale and advance time - this.lightDistance.visible = false; + deltaTime *= this._updateTimeScale( time ); + var clipTime = this._updateTime( deltaTime ); - } else { + // note: _updateTime may disable the action resulting in + // an effective weight of 0 - this.lightDistance.visible = true; - this.lightDistance.scale.set( d, d, d ); + var weight = this._updateWeight( time ); - } - */ + if ( weight > 0 ) { - }; + var interpolants = this._interpolants; + var propertyMixers = this._propertyBindings; - /** - * @author abelnation / http://github.com/abelnation - * @author Mugen87 / http://github.com/Mugen87 - * @author WestLangley / http://github.com/WestLangley - */ + switch ( this.blendMode ) { - function RectAreaLightHelper( light, color ) { + case AdditiveAnimationBlendMode: - Object3D.call( this ); + for ( var j = 0, m = interpolants.length; j !== m; ++ j ) { - this.light = light; - this.light.updateMatrixWorld(); + interpolants[ j ].evaluate( clipTime ); + propertyMixers[ j ].accumulateAdditive( weight ); - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + } - this.color = color; + break; - var material = new LineBasicMaterial( { fog: false } ); + case NormalAnimationBlendMode: + default: - var geometry = new BufferGeometry(); + for ( var j$1 = 0, m$1 = interpolants.length; j$1 !== m$1; ++ j$1 ) { - geometry.addAttribute( 'position', new BufferAttribute( new Float32Array( 5 * 3 ), 3 ) ); + interpolants[ j$1 ].evaluate( clipTime ); + propertyMixers[ j$1 ].accumulate( accuIndex, weight ); - this.line = new Line( geometry, material ); - this.add( this.line ); + } + } - this.update(); + } - } + }, - RectAreaLightHelper.prototype = Object.create( Object3D.prototype ); - RectAreaLightHelper.prototype.constructor = RectAreaLightHelper; + _updateWeight: function ( time ) { - RectAreaLightHelper.prototype.dispose = function () { + var weight = 0; - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); + if ( this.enabled ) { - }; + weight = this.weight; + var interpolant = this._weightInterpolant; - RectAreaLightHelper.prototype.update = function () { + if ( interpolant !== null ) { - // calculate new dimensions of the helper + var interpolantValue = interpolant.evaluate( time )[ 0 ]; - var hx = this.light.width * 0.5; - var hy = this.light.height * 0.5; + weight *= interpolantValue; - var position = this.line.geometry.attributes.position; - var array = position.array; + if ( time > interpolant.parameterPositions[ 1 ] ) { - // update vertices + this.stopFading(); - array[ 0 ] = hx; array[ 1 ] = - hy; array[ 2 ] = 0; - array[ 3 ] = hx; array[ 4 ] = hy; array[ 5 ] = 0; - array[ 6 ] = - hx; array[ 7 ] = hy; array[ 8 ] = 0; - array[ 9 ] = - hx; array[ 10 ] = - hy; array[ 11 ] = 0; - array[ 12 ] = hx; array[ 13 ] = - hy; array[ 14 ] = 0; + if ( interpolantValue === 0 ) { - position.needsUpdate = true; + // faded out, disable + this.enabled = false; - if ( this.color !== undefined ) { + } - this.line.material.color.set( this.color ); + } - } else { + } - this.line.material.color.copy( this.light.color ); + } - } + this._effectiveWeight = weight; + return weight; - }; + }, - /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / https://github.com/Mugen87 - */ + _updateTimeScale: function ( time ) { - function HemisphereLightHelper( light, size, color ) { + var timeScale = 0; - Object3D.call( this ); + if ( ! this.paused ) { - this.light = light; - this.light.updateMatrixWorld(); + timeScale = this.timeScale; - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + var interpolant = this._timeScaleInterpolant; - this.color = color; + if ( interpolant !== null ) { - var geometry = new OctahedronBufferGeometry( size ); - geometry.rotateY( Math.PI * 0.5 ); + var interpolantValue = interpolant.evaluate( time )[ 0 ]; - this.material = new MeshBasicMaterial( { wireframe: true, fog: false } ); - if ( this.color === undefined ) this.material.vertexColors = VertexColors; + timeScale *= interpolantValue; - var position = geometry.getAttribute( 'position' ); - var colors = new Float32Array( position.count * 3 ); + if ( time > interpolant.parameterPositions[ 1 ] ) { - geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) ); + this.stopWarping(); - this.add( new Mesh( geometry, this.material ) ); + if ( timeScale === 0 ) { - this.update(); + // motion has halted, pause + this.paused = true; - } + } else { - HemisphereLightHelper.prototype = Object.create( Object3D.prototype ); - HemisphereLightHelper.prototype.constructor = HemisphereLightHelper; + // warp done - apply final time scale + this.timeScale = timeScale; - HemisphereLightHelper.prototype.dispose = function () { + } - this.children[ 0 ].geometry.dispose(); - this.children[ 0 ].material.dispose(); + } - }; + } - HemisphereLightHelper.prototype.update = function () { + } - var vector = new Vector3(); + this._effectiveTimeScale = timeScale; + return timeScale; - var color1 = new Color(); - var color2 = new Color(); + }, - return function update() { + _updateTime: function ( deltaTime ) { - var mesh = this.children[ 0 ]; + var duration = this._clip.duration; + var loop = this.loop; - if ( this.color !== undefined ) { + var time = this.time + deltaTime; + var loopCount = this._loopCount; - this.material.color.set( this.color ); + var pingPong = ( loop === LoopPingPong ); - } else { + if ( deltaTime === 0 ) { - var colors = mesh.geometry.getAttribute( 'color' ); + if ( loopCount === - 1 ) { return time; } - color1.copy( this.light.color ); - color2.copy( this.light.groundColor ); + return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; - for ( var i = 0, l = colors.count; i < l; i ++ ) { + } - var color = ( i < ( l / 2 ) ) ? color1 : color2; + if ( loop === LoopOnce ) { - colors.setXYZ( i, color.r, color.g, color.b ); + if ( loopCount === - 1 ) { - } + // just started - colors.needsUpdate = true; + this._loopCount = 0; + this._setEndings( true, true, false ); - } + } - mesh.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); + handle_stop: { - }; + if ( time >= duration ) { - }(); + time = duration; - /** - * @author mrdoob / http://mrdoob.com/ - */ + } else if ( time < 0 ) { - function GridHelper( size, divisions, color1, color2 ) { + time = 0; - size = size || 10; - divisions = divisions || 10; - color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); - color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); + } else { - var center = divisions / 2; - var step = size / divisions; - var halfSize = size / 2; + this.time = time; - var vertices = [], colors = []; + break handle_stop; - for ( var 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 ); + if ( this.clampWhenFinished ) { this.paused = true; } + else { this.enabled = false; } - var color = i === center ? color1 : color2; + this.time = time; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; - color.toArray( colors, j ); j += 3; + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime < 0 ? - 1 : 1 + } ); - } + } - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + } else { // repetitive Repeat or PingPong - var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + if ( loopCount === - 1 ) { - LineSegments.call( this, geometry, material ); + // just started - } + if ( deltaTime >= 0 ) { - GridHelper.prototype = Object.create( LineSegments.prototype ); - GridHelper.prototype.constructor = GridHelper; + loopCount = 0; - /** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / http://github.com/Mugen87 - * @author Hectate / http://www.github.com/Hectate - */ + this._setEndings( true, this.repetitions === 0, pingPong ); - function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) { + } else { - radius = radius || 10; - radials = radials || 16; - circles = circles || 8; - divisions = divisions || 64; - color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); - color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); + // when looping in reverse direction, the initial + // transition through zero counts as a repetition, + // so leave loopCount at -1 - var vertices = []; - var colors = []; + this._setEndings( this.repetitions === 0, true, pingPong ); - var x, z; - var v, i, j, r, color; + } - // create the radials + } - for ( i = 0; i <= radials; i ++ ) { + if ( time >= duration || time < 0 ) { - v = ( i / radials ) * ( Math.PI * 2 ); + // wrap around - x = Math.sin( v ) * radius; - z = Math.cos( v ) * radius; + var loopDelta = Math.floor( time / duration ); // signed + time -= duration * loopDelta; - vertices.push( 0, 0, 0 ); - vertices.push( x, 0, z ); + loopCount += Math.abs( loopDelta ); - color = ( i & 1 ) ? color1 : color2; + var pending = this.repetitions - loopCount; - colors.push( color.r, color.g, color.b ); - colors.push( color.r, color.g, color.b ); + if ( pending <= 0 ) { - } + // have to stop (switch state, clamp time, fire event) - // create the circles + if ( this.clampWhenFinished ) { this.paused = true; } + else { this.enabled = false; } - for ( i = 0; i <= circles; i ++ ) { + time = deltaTime > 0 ? duration : 0; - color = ( i & 1 ) ? color1 : color2; + this.time = time; - r = radius - ( radius / circles * i ); + this._mixer.dispatchEvent( { + type: 'finished', action: this, + direction: deltaTime > 0 ? 1 : - 1 + } ); - for ( j = 0; j < divisions; j ++ ) { + } else { - // first vertex + // keep running - v = ( j / divisions ) * ( Math.PI * 2 ); + if ( pending === 1 ) { - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; + // entering the last round - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); + var atStart = deltaTime < 0; + this._setEndings( atStart, ! atStart, pingPong ); - // second vertex + } else { - v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); + this._setEndings( false, false, pingPong ); - x = Math.sin( v ) * r; - z = Math.cos( v ) * r; + } - vertices.push( x, 0, z ); - colors.push( color.r, color.g, color.b ); + this._loopCount = loopCount; - } + this.time = time; - } + this._mixer.dispatchEvent( { + type: 'loop', action: this, loopDelta: loopDelta + } ); - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + } - var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + } else { - LineSegments.call( this, geometry, material ); + this.time = time; - } + } - PolarGridHelper.prototype = Object.create( LineSegments.prototype ); - PolarGridHelper.prototype.constructor = PolarGridHelper; + if ( pingPong && ( loopCount & 1 ) === 1 ) { - /** - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ + // invert time for the "pong round" - function FaceNormalsHelper( object, size, hex, linewidth ) { + return duration - time; - // FaceNormalsHelper only supports THREE.Geometry + } - this.object = object; + } - this.size = ( size !== undefined ) ? size : 1; + return time; - var color = ( hex !== undefined ) ? hex : 0xffff00; + }, - var width = ( linewidth !== undefined ) ? linewidth : 1; + _setEndings: function ( atStart, atEnd, pingPong ) { - // + var settings = this._interpolantSettings; - var nNormals = 0; + if ( pingPong ) { - var objGeometry = this.object.geometry; + settings.endingStart = ZeroSlopeEnding; + settings.endingEnd = ZeroSlopeEnding; - if ( objGeometry && objGeometry.isGeometry ) { + } else { - nNormals = objGeometry.faces.length; + // assuming for LoopOnce atStart == atEnd == true - } else { + if ( atStart ) { - console.warn( 'THREE.FaceNormalsHelper: only THREE.Geometry is supported. Use THREE.VertexNormalsHelper, instead.' ); + settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; - } + } else { - // + settings.endingStart = WrapAroundEnding; - var geometry = new BufferGeometry(); + } - var positions = new Float32BufferAttribute( nNormals * 2 * 3, 3 ); + if ( atEnd ) { - geometry.addAttribute( 'position', positions ); + settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, linewidth: width } ) ); + } else { - // + settings.endingEnd = WrapAroundEnding; - this.matrixAutoUpdate = false; - this.update(); + } - } + } + + }, - FaceNormalsHelper.prototype = Object.create( LineSegments.prototype ); - FaceNormalsHelper.prototype.constructor = FaceNormalsHelper; + _scheduleFading: function ( duration, weightNow, weightThen ) { - FaceNormalsHelper.prototype.update = ( function () { + var mixer = this._mixer, now = mixer.time; + var interpolant = this._weightInterpolant; - var v1 = new Vector3(); - var v2 = new Vector3(); - var normalMatrix = new Matrix3(); + if ( interpolant === null ) { - return function update() { + interpolant = mixer._lendControlInterpolant(); + this._weightInterpolant = interpolant; - this.object.updateMatrixWorld( true ); + } - normalMatrix.getNormalMatrix( this.object.matrixWorld ); + var times = interpolant.parameterPositions, + values = interpolant.sampleValues; - var matrixWorld = this.object.matrixWorld; + times[ 0 ] = now; + values[ 0 ] = weightNow; + times[ 1 ] = now + duration; + values[ 1 ] = weightThen; - var position = this.geometry.attributes.position; + return this; - // + } - var objGeometry = this.object.geometry; + } ); - var vertices = objGeometry.vertices; + function AnimationMixer( root ) { - var faces = objGeometry.faces; + this._root = root; + this._initMemoryManager(); + this._accuIndex = 0; - var idx = 0; + this.time = 0; - for ( var i = 0, l = faces.length; i < l; i ++ ) { + this.timeScale = 1.0; - var face = faces[ i ]; + } - var normal = face.normal; + AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototype ), { - v1.copy( vertices[ face.a ] ) - .add( vertices[ face.b ] ) - .add( vertices[ face.c ] ) - .divideScalar( 3 ) - .applyMatrix4( matrixWorld ); + constructor: AnimationMixer, - v2.copy( normal ).applyMatrix3( normalMatrix ).normalize().multiplyScalar( this.size ).add( v1 ); + _bindAction: function ( action, prototypeAction ) { - position.setXYZ( idx, v1.x, v1.y, v1.z ); + var root = action._localRoot || this._root, + tracks = action._clip.tracks, + nTracks = tracks.length, + bindings = action._propertyBindings, + interpolants = action._interpolants, + rootUuid = root.uuid, + bindingsByRoot = this._bindingsByRootAndName; - idx = idx + 1; + var bindingsByName = bindingsByRoot[ rootUuid ]; - position.setXYZ( idx, v2.x, v2.y, v2.z ); + if ( bindingsByName === undefined ) { - idx = idx + 1; + bindingsByName = {}; + bindingsByRoot[ rootUuid ] = bindingsByName; } - position.needsUpdate = true; + for ( var i = 0; i !== nTracks; ++ i ) { - }; + var track = tracks[ i ], + trackName = track.name; - }() ); + var binding = bindingsByName[ trackName ]; - /** - * @author alteredq / http://alteredqualia.com/ - * @author mrdoob / http://mrdoob.com/ - * @author WestLangley / http://github.com/WestLangley - */ + if ( binding !== undefined ) { - function DirectionalLightHelper( light, size, color ) { + bindings[ i ] = binding; - Object3D.call( this ); + } else { - this.light = light; - this.light.updateMatrixWorld(); + binding = bindings[ i ]; - this.matrix = light.matrixWorld; - this.matrixAutoUpdate = false; + if ( binding !== undefined ) { - this.color = color; + // existing binding, make sure the cache knows - if ( size === undefined ) size = 1; + if ( binding._cacheIndex === null ) { - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( [ - - size, size, 0, - size, size, 0, - size, - size, 0, - - size, - size, 0, - - size, size, 0 - ], 3 ) ); + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); - var material = new LineBasicMaterial( { fog: false } ); + } - this.lightPlane = new Line( geometry, material ); - this.add( this.lightPlane ); + continue; - geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); + } - this.targetLine = new Line( geometry, material ); - this.add( this.targetLine ); + var path = prototypeAction && prototypeAction. + _propertyBindings[ i ].binding.parsedPath; - this.update(); + binding = new PropertyMixer( + PropertyBinding.create( root, trackName, path ), + track.ValueTypeName, track.getValueSize() ); - } + ++ binding.referenceCount; + this._addInactiveBinding( binding, rootUuid, trackName ); - DirectionalLightHelper.prototype = Object.create( Object3D.prototype ); - DirectionalLightHelper.prototype.constructor = DirectionalLightHelper; + bindings[ i ] = binding; - DirectionalLightHelper.prototype.dispose = function () { + } - this.lightPlane.geometry.dispose(); - this.lightPlane.material.dispose(); - this.targetLine.geometry.dispose(); - this.targetLine.material.dispose(); + interpolants[ i ].resultBuffer = binding.buffer; - }; + } - DirectionalLightHelper.prototype.update = function () { + }, - var v1 = new Vector3(); - var v2 = new Vector3(); - var v3 = new Vector3(); + _activateAction: function ( action ) { - return function update() { + if ( ! this._isActiveAction( action ) ) { - v1.setFromMatrixPosition( this.light.matrixWorld ); - v2.setFromMatrixPosition( this.light.target.matrixWorld ); - v3.subVectors( v2, v1 ); + if ( action._cacheIndex === null ) { - this.lightPlane.lookAt( v3 ); + // this action has been forgotten by the cache, but the user + // appears to be still using it -> rebind - if ( this.color !== undefined ) { + var rootUuid = ( action._localRoot || this._root ).uuid, + clipUuid = action._clip.uuid, + actionsForClip = this._actionsByClip[ clipUuid ]; - this.lightPlane.material.color.set( this.color ); - this.targetLine.material.color.set( this.color ); + this._bindAction( action, + actionsForClip && actionsForClip.knownActions[ 0 ] ); - } else { + this._addInactiveAction( action, clipUuid, rootUuid ); - this.lightPlane.material.color.copy( this.light.color ); - this.targetLine.material.color.copy( this.light.color ); + } - } + var bindings = action._propertyBindings; - this.targetLine.lookAt( v3 ); - this.targetLine.scale.z = v3.length(); + // increment reference counts / sort out state + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { - }; + var binding = bindings[ i ]; - }(); + if ( binding.useCount ++ === 0 ) { - /** - * @author alteredq / http://alteredqualia.com/ - * @author Mugen87 / https://github.com/Mugen87 - * - * - 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 - */ + this._lendBinding( binding ); + binding.saveOriginalState(); - function CameraHelper( camera ) { + } - var geometry = new BufferGeometry(); - var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: FaceColors } ); + } - var vertices = []; - var colors = []; + this._lendAction( action ); - var pointMap = {}; + } - // colors + }, - var colorFrustum = new Color( 0xffaa00 ); - var colorCone = new Color( 0xff0000 ); - var colorUp = new Color( 0x00aaff ); - var colorTarget = new Color( 0xffffff ); - var colorCross = new Color( 0x333333 ); + _deactivateAction: function ( action ) { - // near + if ( this._isActiveAction( action ) ) { - addLine( 'n1', 'n2', colorFrustum ); - addLine( 'n2', 'n4', colorFrustum ); - addLine( 'n4', 'n3', colorFrustum ); - addLine( 'n3', 'n1', colorFrustum ); + var bindings = action._propertyBindings; - // far + // decrement reference counts / sort out state + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { - addLine( 'f1', 'f2', colorFrustum ); - addLine( 'f2', 'f4', colorFrustum ); - addLine( 'f4', 'f3', colorFrustum ); - addLine( 'f3', 'f1', colorFrustum ); + var binding = bindings[ i ]; - // sides + if ( -- binding.useCount === 0 ) { - addLine( 'n1', 'f1', colorFrustum ); - addLine( 'n2', 'f2', colorFrustum ); - addLine( 'n3', 'f3', colorFrustum ); - addLine( 'n4', 'f4', colorFrustum ); + binding.restoreOriginalState(); + this._takeBackBinding( binding ); - // cone + } - addLine( 'p', 'n1', colorCone ); - addLine( 'p', 'n2', colorCone ); - addLine( 'p', 'n3', colorCone ); - addLine( 'p', 'n4', colorCone ); + } - // up + this._takeBackAction( action ); - addLine( 'u1', 'u2', colorUp ); - addLine( 'u2', 'u3', colorUp ); - addLine( 'u3', 'u1', colorUp ); + } - // target + }, - addLine( 'c', 't', colorTarget ); - addLine( 'p', 'c', colorCross ); + // Memory manager - // cross + _initMemoryManager: function () { - addLine( 'cn1', 'cn2', colorCross ); - addLine( 'cn3', 'cn4', colorCross ); + this._actions = []; // 'nActiveActions' followed by inactive ones + this._nActiveActions = 0; - addLine( 'cf1', 'cf2', colorCross ); - addLine( 'cf3', 'cf4', colorCross ); + this._actionsByClip = {}; + // inside: + // { + // knownActions: Array< AnimationAction > - used as prototypes + // actionByRoot: AnimationAction - lookup + // } - function addLine( a, b, color ) { - addPoint( a, color ); - addPoint( b, color ); + this._bindings = []; // 'nActiveBindings' followed by inactive ones + this._nActiveBindings = 0; - } + this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > - function addPoint( id, color ) { - vertices.push( 0, 0, 0 ); - colors.push( color.r, color.g, color.b ); + this._controlInterpolants = []; // same game as above + this._nActiveControlInterpolants = 0; - if ( pointMap[ id ] === undefined ) { + var scope = this; - pointMap[ id ] = []; + this.stats = { - } + actions: { + get total() { - pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); + return scope._actions.length; - } + }, + get inUse() { - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + return scope._nActiveActions; - LineSegments.call( this, geometry, material ); + } + }, + bindings: { + get total() { - this.camera = camera; - if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); + return scope._bindings.length; - this.matrix = camera.matrixWorld; - this.matrixAutoUpdate = false; + }, + get inUse() { - this.pointMap = pointMap; + return scope._nActiveBindings; - this.update(); + } + }, + controlInterpolants: { + get total() { - } + return scope._controlInterpolants.length; - CameraHelper.prototype = Object.create( LineSegments.prototype ); - CameraHelper.prototype.constructor = CameraHelper; + }, + get inUse() { - CameraHelper.prototype.update = function () { + return scope._nActiveControlInterpolants; - var geometry, pointMap; + } + } - var vector = new Vector3(); - var camera = new Camera(); + }; - function setPoint( point, x, y, z ) { + }, - vector.set( x, y, z ).unproject( camera ); + // Memory management for AnimationAction objects - var points = pointMap[ point ]; + _isActiveAction: function ( action ) { - if ( points !== undefined ) { + var index = action._cacheIndex; + return index !== null && index < this._nActiveActions; - var position = geometry.getAttribute( 'position' ); + }, - for ( var i = 0, l = points.length; i < l; i ++ ) { + _addInactiveAction: function ( action, clipUuid, rootUuid ) { - position.setXYZ( points[ i ], vector.x, vector.y, vector.z ); + var actions = this._actions, + actionsByClip = this._actionsByClip; - } + var actionsForClip = actionsByClip[ clipUuid ]; - } + if ( actionsForClip === undefined ) { - } + actionsForClip = { - return function update() { + knownActions: [ action ], + actionByRoot: {} - geometry = this.geometry; - pointMap = this.pointMap; + }; - var w = 1, h = 1; + action._byClipCacheIndex = 0; - // we need just camera projection matrix - // world matrix must be identity + actionsByClip[ clipUuid ] = actionsForClip; - camera.projectionMatrix.copy( this.camera.projectionMatrix ); + } else { - // center / target + var knownActions = actionsForClip.knownActions; - setPoint( 'c', 0, 0, - 1 ); - setPoint( 't', 0, 0, 1 ); + action._byClipCacheIndex = knownActions.length; + knownActions.push( action ); - // near + } - setPoint( 'n1', - w, - h, - 1 ); - setPoint( 'n2', w, - h, - 1 ); - setPoint( 'n3', - w, h, - 1 ); - setPoint( 'n4', w, h, - 1 ); + action._cacheIndex = actions.length; + actions.push( action ); - // far + actionsForClip.actionByRoot[ rootUuid ] = action; - setPoint( 'f1', - w, - h, 1 ); - setPoint( 'f2', w, - h, 1 ); - setPoint( 'f3', - w, h, 1 ); - setPoint( 'f4', w, h, 1 ); + }, - // up + _removeInactiveAction: function ( action ) { - setPoint( 'u1', w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', 0, h * 2, - 1 ); + var actions = this._actions, + lastInactiveAction = actions[ actions.length - 1 ], + cacheIndex = action._cacheIndex; - // cross + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); - setPoint( 'cf1', - w, 0, 1 ); - setPoint( 'cf2', w, 0, 1 ); - setPoint( 'cf3', 0, - h, 1 ); - setPoint( 'cf4', 0, h, 1 ); + action._cacheIndex = null; - setPoint( 'cn1', - w, 0, - 1 ); - setPoint( 'cn2', w, 0, - 1 ); - setPoint( 'cn3', 0, - h, - 1 ); - setPoint( 'cn4', 0, h, - 1 ); - geometry.getAttribute( 'position' ).needsUpdate = true; + var clipUuid = action._clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ], + knownActionsForClip = actionsForClip.knownActions, - }; + lastKnownAction = + knownActionsForClip[ knownActionsForClip.length - 1 ], - }(); + byClipCacheIndex = action._byClipCacheIndex; - /** - * @author mrdoob / http://mrdoob.com/ - * @author Mugen87 / http://github.com/Mugen87 - */ + lastKnownAction._byClipCacheIndex = byClipCacheIndex; + knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; + knownActionsForClip.pop(); - function BoxHelper( object, color ) { + action._byClipCacheIndex = null; - this.object = object; - if ( color === undefined ) color = 0xffff00; + var actionByRoot = actionsForClip.actionByRoot, + rootUuid = ( action._localRoot || this._root ).uuid; - var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); - var positions = new Float32Array( 8 * 3 ); + delete actionByRoot[ rootUuid ]; - var geometry = new BufferGeometry(); - geometry.setIndex( new BufferAttribute( indices, 1 ) ); - geometry.addAttribute( 'position', new BufferAttribute( positions, 3 ) ); + if ( knownActionsForClip.length === 0 ) { - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); + delete actionsByClip[ clipUuid ]; - this.matrixAutoUpdate = false; + } - this.update(); + this._removeInactiveBindingsForAction( action ); - } + }, - BoxHelper.prototype = Object.create( LineSegments.prototype ); - BoxHelper.prototype.constructor = BoxHelper; + _removeInactiveBindingsForAction: function ( action ) { - BoxHelper.prototype.update = ( function () { + var bindings = action._propertyBindings; + + for ( var i = 0, n = bindings.length; i !== n; ++ i ) { - var box = new Box3(); + var binding = bindings[ i ]; - return function update( object ) { + if ( -- binding.referenceCount === 0 ) { - if ( object !== undefined ) { + this._removeInactiveBinding( binding ); - console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); + } } - if ( this.object !== undefined ) { - - box.setFromObject( this.object ); + }, - } + _lendAction: function ( action ) { - if ( box.isEmpty() ) return; + // [ active actions | inactive actions ] + // [ active actions >| inactive actions ] + // s a + // <-swap-> + // a s - var min = box.min; - var max = box.max; + var actions = this._actions, + prevIndex = action._cacheIndex, - /* - 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 - */ - - var position = this.geometry.attributes.position; - var 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(); + lastActiveIndex = this._nActiveActions ++, - }; + firstInactiveAction = actions[ lastActiveIndex ]; - } )(); + action._cacheIndex = lastActiveIndex; + actions[ lastActiveIndex ] = action; - BoxHelper.prototype.setFromObject = function ( object ) { + firstInactiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = firstInactiveAction; - this.object = object; - this.update(); + }, - return this; + _takeBackAction: function ( action ) { - }; + // [ active actions | inactive actions ] + // [ active actions |< inactive actions ] + // a s + // <-swap-> + // s a - BoxHelper.prototype.copy = function ( source ) { + var actions = this._actions, + prevIndex = action._cacheIndex, - LineSegments.prototype.copy.call( this, source ); + firstInactiveIndex = -- this._nActiveActions, - this.object = source.object; + lastActiveAction = actions[ firstInactiveIndex ]; - return this; + action._cacheIndex = firstInactiveIndex; + actions[ firstInactiveIndex ] = action; - }; + lastActiveAction._cacheIndex = prevIndex; + actions[ prevIndex ] = lastActiveAction; - BoxHelper.prototype.clone = function () { + }, - return new this.constructor().copy( this ); + // Memory management for PropertyMixer objects - }; + _addInactiveBinding: function ( binding, rootUuid, trackName ) { - /** - * @author WestLangley / http://github.com/WestLangley - */ + var bindingsByRoot = this._bindingsByRootAndName, + bindings = this._bindings; - function Box3Helper( box, hex ) { + var bindingByName = bindingsByRoot[ rootUuid ]; - this.type = 'Box3Helper'; + if ( bindingByName === undefined ) { - this.box = box; + bindingByName = {}; + bindingsByRoot[ rootUuid ] = bindingByName; - var color = ( hex !== undefined ) ? hex : 0xffff00; + } - var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + bindingByName[ trackName ] = binding; - var 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 ]; + binding._cacheIndex = bindings.length; + bindings.push( binding ); - var geometry = new BufferGeometry(); + }, - geometry.setIndex( new BufferAttribute( indices, 1 ) ); + _removeInactiveBinding: function ( binding ) { - geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + var bindings = this._bindings, + propBinding = binding.binding, + rootUuid = propBinding.rootNode.uuid, + trackName = propBinding.path, + bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ], - LineSegments.call( this, geometry, new LineBasicMaterial( { color: color } ) ); + lastInactiveBinding = bindings[ bindings.length - 1 ], + cacheIndex = binding._cacheIndex; - this.geometry.computeBoundingSphere(); + lastInactiveBinding._cacheIndex = cacheIndex; + bindings[ cacheIndex ] = lastInactiveBinding; + bindings.pop(); - } + delete bindingByName[ trackName ]; - Box3Helper.prototype = Object.create( LineSegments.prototype ); - Box3Helper.prototype.constructor = Box3Helper; + if ( Object.keys( bindingByName ).length === 0 ) { - Box3Helper.prototype.updateMatrixWorld = function ( force ) { + delete bindingsByRoot[ rootUuid ]; - var box = this.box; + } - if ( box.isEmpty() ) return; + }, - box.getCenter( this.position ); + _lendBinding: function ( binding ) { - box.getSize( this.scale ); + var bindings = this._bindings, + prevIndex = binding._cacheIndex, - this.scale.multiplyScalar( 0.5 ); + lastActiveIndex = this._nActiveBindings ++, - Object3D.prototype.updateMatrixWorld.call( this, force ); + firstInactiveBinding = bindings[ lastActiveIndex ]; - }; + binding._cacheIndex = lastActiveIndex; + bindings[ lastActiveIndex ] = binding; - /** - * @author WestLangley / http://github.com/WestLangley - */ + firstInactiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = firstInactiveBinding; - function PlaneHelper( plane, size, hex ) { + }, - this.type = 'PlaneHelper'; + _takeBackBinding: function ( binding ) { - this.plane = plane; + var bindings = this._bindings, + prevIndex = binding._cacheIndex, - this.size = ( size === undefined ) ? 1 : size; + firstInactiveIndex = -- this._nActiveBindings, - var color = ( hex !== undefined ) ? hex : 0xffff00; + lastActiveBinding = bindings[ firstInactiveIndex ]; - var 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 ]; + binding._cacheIndex = firstInactiveIndex; + bindings[ firstInactiveIndex ] = binding; - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - geometry.computeBoundingSphere(); + lastActiveBinding._cacheIndex = prevIndex; + bindings[ prevIndex ] = lastActiveBinding; - Line.call( this, geometry, new LineBasicMaterial( { color: color } ) ); + }, - // - var positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ]; + // Memory management of Interpolants for weight and time scale - var geometry2 = new BufferGeometry(); - geometry2.addAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); - geometry2.computeBoundingSphere(); + _lendControlInterpolant: function () { - this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false } ) ) ); + var interpolants = this._controlInterpolants, + lastActiveIndex = this._nActiveControlInterpolants ++; - } + var interpolant = interpolants[ lastActiveIndex ]; - PlaneHelper.prototype = Object.create( Line.prototype ); - PlaneHelper.prototype.constructor = PlaneHelper; + if ( interpolant === undefined ) { - PlaneHelper.prototype.updateMatrixWorld = function ( force ) { + interpolant = new LinearInterpolant( + new Float32Array( 2 ), new Float32Array( 2 ), + 1, this._controlInterpolantsResultBuffer ); - var scale = - this.plane.constant; + interpolant.__cacheIndex = lastActiveIndex; + interpolants[ lastActiveIndex ] = interpolant; - 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 ); + return interpolant; - this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here + }, - this.lookAt( this.plane.normal ); + _takeBackControlInterpolant: function ( interpolant ) { - Object3D.prototype.updateMatrixWorld.call( this, force ); + var interpolants = this._controlInterpolants, + prevIndex = interpolant.__cacheIndex, - }; + firstInactiveIndex = -- this._nActiveControlInterpolants, - /** - * @author WestLangley / http://github.com/WestLangley - * @author zz85 / http://github.com/zz85 - * @author bhouston / http://clara.io - * - * Creates an arrow for visualizing directions - * - * Parameters: - * dir - Vector3 - * origin - Vector3 - * length - Number - * color - color in hex value - * headLength - Number - * headWidth - Number - */ + lastActiveInterpolant = interpolants[ firstInactiveIndex ]; - var lineGeometry, coneGeometry; + interpolant.__cacheIndex = firstInactiveIndex; + interpolants[ firstInactiveIndex ] = interpolant; - function ArrowHelper( dir, origin, length, color, headLength, headWidth ) { + lastActiveInterpolant.__cacheIndex = prevIndex; + interpolants[ prevIndex ] = lastActiveInterpolant; - // dir is assumed to be normalized + }, - Object3D.call( this ); + _controlInterpolantsResultBuffer: new Float32Array( 1 ), - if ( dir === undefined ) dir = new THREE.Vector3( 0, 0, 1 ); - if ( origin === undefined ) origin = new THREE.Vector3( 0, 0, 0 ); - if ( length === undefined ) length = 1; - if ( color === undefined ) color = 0xffff00; - if ( headLength === undefined ) headLength = 0.2 * length; - if ( headWidth === undefined ) headWidth = 0.2 * headLength; + // 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: function ( clip, optionalRoot, blendMode ) { - if ( lineGeometry === undefined ) { + var root = optionalRoot || this._root, + rootUuid = root.uuid; - lineGeometry = new BufferGeometry(); - lineGeometry.addAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); + var clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; - coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 ); - coneGeometry.translate( 0, - 0.5, 0 ); + var clipUuid = clipObject !== null ? clipObject.uuid : clip; - } + var actionsForClip = this._actionsByClip[ clipUuid ], + prototypeAction = null; - this.position.copy( origin ); + if ( blendMode === undefined ) { - this.line = new Line( lineGeometry, new LineBasicMaterial( { color: color } ) ); - this.line.matrixAutoUpdate = false; - this.add( this.line ); + if ( clipObject !== null ) { - this.cone = new Mesh( coneGeometry, new MeshBasicMaterial( { color: color } ) ); - this.cone.matrixAutoUpdate = false; - this.add( this.cone ); + blendMode = clipObject.blendMode; - this.setDirection( dir ); - this.setLength( length, headLength, headWidth ); + } else { - } + blendMode = NormalAnimationBlendMode; - ArrowHelper.prototype = Object.create( Object3D.prototype ); - ArrowHelper.prototype.constructor = ArrowHelper; + } - ArrowHelper.prototype.setDirection = ( function () { + } - var axis = new Vector3(); - var radians; + if ( actionsForClip !== undefined ) { - return function setDirection( dir ) { + var existingAction = actionsForClip.actionByRoot[ rootUuid ]; - // dir is assumed to be normalized + if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { - if ( dir.y > 0.99999 ) { + return existingAction; - this.quaternion.set( 0, 0, 0, 1 ); + } - } else if ( dir.y < - 0.99999 ) { + // we know the clip, so we don't have to parse all + // the bindings again but can just copy + prototypeAction = actionsForClip.knownActions[ 0 ]; - this.quaternion.set( 1, 0, 0, 0 ); + // also, take the clip from the prototype action + if ( clipObject === null ) + { clipObject = prototypeAction._clip; } - } else { + } - axis.set( dir.z, 0, - dir.x ).normalize(); + // clip must be known when specified via string + if ( clipObject === null ) { return null; } - radians = Math.acos( dir.y ); + // allocate all resources required to run it + var newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); - this.quaternion.setFromAxisAngle( axis, radians ); + this._bindAction( newAction, prototypeAction ); - } + // and make the action known to the memory manager + this._addInactiveAction( newAction, clipUuid, rootUuid ); - }; + return newAction; - }() ); + }, - ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { + // get an existing action + existingAction: function ( clip, optionalRoot ) { - if ( headLength === undefined ) headLength = 0.2 * length; - if ( headWidth === undefined ) headWidth = 0.2 * headLength; + var root = optionalRoot || this._root, + rootUuid = root.uuid, - this.line.scale.set( 1, Math.max( 0, length - headLength ), 1 ); - this.line.updateMatrix(); + clipObject = typeof clip === 'string' ? + AnimationClip.findByName( root, clip ) : clip, - this.cone.scale.set( headWidth, headLength, headWidth ); - this.cone.position.y = length; - this.cone.updateMatrix(); + clipUuid = clipObject ? clipObject.uuid : clip, - }; + actionsForClip = this._actionsByClip[ clipUuid ]; - ArrowHelper.prototype.setColor = function ( color ) { + if ( actionsForClip !== undefined ) { - this.line.material.color.copy( color ); - this.cone.material.color.copy( color ); + return actionsForClip.actionByRoot[ rootUuid ] || null; - }; + } - ArrowHelper.prototype.copy = function ( source ) { + return null; - Object3D.prototype.copy.call( this, source, false ); + }, - this.line.copy( source.line ); - this.cone.copy( source.cone ); + // deactivates all previously scheduled actions + stopAllAction: function () { - return this; + var actions = this._actions, + nActions = this._nActiveActions; - }; + for ( var i = nActions - 1; i >= 0; -- i ) { - ArrowHelper.prototype.clone = function () { + actions[ i ].stop(); - return new this.constructor().copy( this ); + } - }; + return this; - /** - * @author sroucheray / http://sroucheray.org/ - * @author mrdoob / http://mrdoob.com/ - */ + }, - function AxesHelper( size ) { + // advance the time and update apply the animation + update: function ( deltaTime ) { - size = size || 1; + deltaTime *= this.timeScale; - var vertices = [ - 0, 0, 0, size, 0, 0, - 0, 0, 0, 0, size, 0, - 0, 0, 0, 0, 0, size - ]; + var actions = this._actions, + nActions = this._nActiveActions, - var colors = [ - 1, 0, 0, 1, 0.6, 0, - 0, 1, 0, 0.6, 1, 0, - 0, 0, 1, 0, 0.6, 1 - ]; + time = this.time += deltaTime, + timeDirection = Math.sign( deltaTime ), - var geometry = new BufferGeometry(); - geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); - geometry.addAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + accuIndex = this._accuIndex ^= 1; - var material = new LineBasicMaterial( { vertexColors: VertexColors } ); + // run active actions - LineSegments.call( this, geometry, material ); + for ( var i = 0; i !== nActions; ++ i ) { - } + var action = actions[ i ]; - AxesHelper.prototype = Object.create( LineSegments.prototype ); - AxesHelper.prototype.constructor = AxesHelper; + action._update( time, deltaTime, timeDirection, accuIndex ); - /** - * @author mrdoob / http://mrdoob.com/ - */ + } - function Face4( a, b, c, d, normal, color, materialIndex ) { + // update scene graph - console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ); - return new Face3( a, b, c, normal, color, materialIndex ); + var bindings = this._bindings, + nBindings = this._nActiveBindings; - } + for ( var i$1 = 0; i$1 !== nBindings; ++ i$1 ) { - var LineStrip = 0; + bindings[ i$1 ].apply( accuIndex ); - var LinePieces = 1; + } - function MeshFaceMaterial( materials ) { + return this; - console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' ); - return materials; + }, - } + // Allows you to seek to a specific time in an animation. + setTime: function ( timeInSeconds ) { - function MultiMaterial( materials ) { + this.time = 0; // Zero out time attribute for AnimationMixer object; + for ( var i = 0; i < this._actions.length; i ++ ) { - if ( materials === undefined ) materials = []; + this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. - console.warn( 'THREE.MultiMaterial has been removed. Use an Array instead.' ); - materials.isMultiMaterial = true; - materials.materials = materials; - materials.clone = function () { + } - return materials.slice(); + return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. - }; - return materials; + }, - } + // return this mixer's root target object + getRoot: function () { - function PointCloud( geometry, material ) { + return this._root; - console.warn( 'THREE.PointCloud has been renamed to THREE.Points.' ); - return new Points( geometry, material ); + }, - } + // free all resources specific to a particular clip + uncacheClip: function ( clip ) { - function Particle( material ) { + var actions = this._actions, + clipUuid = clip.uuid, + actionsByClip = this._actionsByClip, + actionsForClip = actionsByClip[ clipUuid ]; - console.warn( 'THREE.Particle has been renamed to THREE.Sprite.' ); - return new Sprite( material ); + if ( actionsForClip !== undefined ) { - } + // note: just calling _removeInactiveAction would mess up the + // iteration state and also require updating the state we can + // just throw away - function ParticleSystem( geometry, material ) { + var actionsToRemove = actionsForClip.knownActions; - console.warn( 'THREE.ParticleSystem has been renamed to THREE.Points.' ); - return new Points( geometry, material ); + for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) { - } + var action = actionsToRemove[ i ]; - function PointCloudMaterial( parameters ) { + this._deactivateAction( action ); - console.warn( 'THREE.PointCloudMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); + var cacheIndex = action._cacheIndex, + lastInactiveAction = actions[ actions.length - 1 ]; - } + action._cacheIndex = null; + action._byClipCacheIndex = null; - function ParticleBasicMaterial( parameters ) { + lastInactiveAction._cacheIndex = cacheIndex; + actions[ cacheIndex ] = lastInactiveAction; + actions.pop(); - console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); + this._removeInactiveBindingsForAction( action ); - } + } - function ParticleSystemMaterial( parameters ) { + delete actionsByClip[ clipUuid ]; - console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointsMaterial.' ); - return new PointsMaterial( parameters ); + } - } + }, - function Vertex( x, y, z ) { + // free all resources specific to a particular root target object + uncacheRoot: function ( root ) { - console.warn( 'THREE.Vertex has been removed. Use THREE.Vector3 instead.' ); - return new Vector3( x, y, z ); + var rootUuid = root.uuid, + actionsByClip = this._actionsByClip; - } + for ( var clipUuid in actionsByClip ) { - // + var actionByRoot = actionsByClip[ clipUuid ].actionByRoot, + action = actionByRoot[ rootUuid ]; - function DynamicBufferAttribute( array, itemSize ) { + if ( action !== undefined ) { - console.warn( 'THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setDynamic( true ) instead.' ); - return new BufferAttribute( array, itemSize ).setDynamic( true ); + this._deactivateAction( action ); + this._removeInactiveAction( action ); - } + } - function Int8Attribute( array, itemSize ) { + } - console.warn( 'THREE.Int8Attribute has been removed. Use new THREE.Int8BufferAttribute() instead.' ); - return new Int8BufferAttribute( array, itemSize ); + var bindingsByRoot = this._bindingsByRootAndName, + bindingByName = bindingsByRoot[ rootUuid ]; - } + if ( bindingByName !== undefined ) { - function Uint8Attribute( array, itemSize ) { + for ( var trackName in bindingByName ) { - console.warn( 'THREE.Uint8Attribute has been removed. Use new THREE.Uint8BufferAttribute() instead.' ); - return new Uint8BufferAttribute( array, itemSize ); + var binding = bindingByName[ trackName ]; + binding.restoreOriginalState(); + this._removeInactiveBinding( binding ); - } + } - function Uint8ClampedAttribute( array, itemSize ) { + } - console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use new THREE.Uint8ClampedBufferAttribute() instead.' ); - return new Uint8ClampedBufferAttribute( array, itemSize ); + }, - } + // remove a targeted clip from the cache + uncacheAction: function ( clip, optionalRoot ) { - function Int16Attribute( array, itemSize ) { + var action = this.existingAction( clip, optionalRoot ); - console.warn( 'THREE.Int16Attribute has been removed. Use new THREE.Int16BufferAttribute() instead.' ); - return new Int16BufferAttribute( array, itemSize ); + if ( action !== null ) { - } + this._deactivateAction( action ); + this._removeInactiveAction( action ); - 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 ) { + function Uniform( value ) { - console.warn( 'THREE.Int32Attribute has been removed. Use new THREE.Int32BufferAttribute() instead.' ); - return new Int32BufferAttribute( array, itemSize ); + if ( typeof value === 'string' ) { - } + console.warn( 'THREE.Uniform: Type parameter is no longer needed.' ); + value = arguments[ 1 ]; - function Uint32Attribute( array, itemSize ) { + } - console.warn( 'THREE.Uint32Attribute has been removed. Use new THREE.Uint32BufferAttribute() instead.' ); - return new Uint32BufferAttribute( array, itemSize ); + this.value = value; } - function Float32Attribute( array, itemSize ) { + Uniform.prototype.clone = function () { - console.warn( 'THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead.' ); - return new Float32BufferAttribute( array, itemSize ); + return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); - } + }; - function Float64Attribute( array, itemSize ) { + function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) { - console.warn( 'THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead.' ); - return new Float64BufferAttribute( array, itemSize ); + InterleavedBuffer.call( this, array, stride ); + + this.meshPerAttribute = meshPerAttribute || 1; } - // + InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), { - Curve.create = function ( construct, getPoint ) { + constructor: InstancedInterleavedBuffer, - console.log( 'THREE.Curve.create() has been deprecated' ); + isInstancedInterleavedBuffer: true, - construct.prototype = Object.create( Curve.prototype ); - construct.prototype.constructor = construct; - construct.prototype.getPoint = getPoint; + copy: function ( source ) { - return construct; + InterleavedBuffer.prototype.copy.call( this, source ); - }; + this.meshPerAttribute = source.meshPerAttribute; - // + return this; - Object.assign( CurvePath.prototype, { + }, - createPointsGeometry: function ( divisions ) { + clone: function ( data ) { - console.warn( 'THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + var ib = InterleavedBuffer.prototype.clone.call( this, data ); - // generate geometry from path points (for Line or Points objects) + ib.meshPerAttribute = this.meshPerAttribute; - var pts = this.getPoints( divisions ); - return this.createGeometry( pts ); + return ib; }, - createSpacedPointsGeometry: function ( divisions ) { + toJSON: function ( data ) { - console.warn( 'THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + var json = InterleavedBuffer.prototype.toJSON.call( this, data ); - // generate geometry from equidistant sampling along the path + json.isInstancedInterleavedBuffer = true; + json.meshPerAttribute = this.meshPerAttribute; - var pts = this.getSpacedPoints( divisions ); - return this.createGeometry( pts ); + return json; - }, + } - createGeometry: function ( points ) { + } ); - console.warn( 'THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + function Raycaster( origin, direction, near, far ) { - var geometry = new Geometry(); + this.ray = new Ray( origin, direction ); + // direction is assumed to be normalized (for accurate distance calculations) - for ( var i = 0, l = points.length; i < l; i ++ ) { + this.near = near || 0; + this.far = far || Infinity; + this.camera = null; + this.layers = new Layers(); - var point = points[ i ]; - geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); + this.params = { + Mesh: {}, + Line: { threshold: 1 }, + LOD: {}, + Points: { threshold: 1 }, + Sprite: {} + }; + + Object.defineProperties( this.params, { + PointCloud: { + get: function () { + + console.warn( 'THREE.Raycaster: params.PointCloud has been renamed to params.Points.' ); + return this.Points; + } } + } ); - return geometry; + } - } + function ascSort( a, b ) { - } ); + return a.distance - b.distance; - // + } - Object.assign( Path.prototype, { + function intersectObject( object, raycaster, intersects, recursive ) { - fromPoints: function ( points ) { + if ( object.layers.test( raycaster.layers ) ) { - console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' ); - this.setFromPoints( points ); + object.raycast( raycaster, intersects ); } - } ); + if ( recursive === true ) { - // + var children = object.children; - function ClosedSplineCurve3( points ) { + for ( var i = 0, l = children.length; i < l; i ++ ) { - console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); + intersectObject( children[ i ], raycaster, intersects, true ); - CatmullRomCurve3.call( this, points ); - this.type = 'catmullrom'; - this.closed = true; + } + + } } - ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); + Object.assign( Raycaster.prototype, { - // + set: function ( origin, direction ) { - function SplineCurve3( points ) { + // direction is assumed to be normalized (for accurate distance calculations) - console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); + this.ray.set( origin, direction ); - CatmullRomCurve3.call( this, points ); - this.type = 'catmullrom'; + }, - } + setFromCamera: function ( coords, camera ) { - SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); + 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; - function Spline( points ) { + } else if ( ( camera && camera.isOrthographicCamera ) ) { - console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' ); + 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; - CatmullRomCurve3.call( this, points ); - this.type = 'catmullrom'; + } else { - } + console.error( 'THREE.Raycaster: Unsupported camera type.' ); - Spline.prototype = Object.create( CatmullRomCurve3.prototype ); + } - Object.assign( Spline.prototype, { + }, - initFromArray: function ( /* a */ ) { + intersectObject: function ( object, recursive, optionalTarget ) { - console.error( 'THREE.Spline: .initFromArray() has been removed.' ); + var intersects = optionalTarget || []; - }, - getControlPointsArray: function ( /* optionalTarget */ ) { + intersectObject( object, this, intersects, recursive ); - console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' ); + intersects.sort( ascSort ); - }, - reparametrizeByArcLength: function ( /* samplingCoef */ ) { + return intersects; - console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' ); + }, - } + intersectObjects: function ( objects, recursive, optionalTarget ) { - } ); + var intersects = optionalTarget || []; - // + if ( Array.isArray( objects ) === false ) { - function AxisHelper( size ) { + console.warn( 'THREE.Raycaster.intersectObjects: objects is not an Array.' ); + return intersects; - console.warn( 'THREE.AxisHelper has been renamed to THREE.AxesHelper.' ); - return new AxesHelper( size ); + } - } + for ( var i = 0, l = objects.length; i < l; i ++ ) { - function BoundingBoxHelper( object, color ) { + intersectObject( objects[ i ], this, intersects, recursive ); - console.warn( 'THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead.' ); - return new BoxHelper( object, color ); + } - } + intersects.sort( ascSort ); - function EdgesHelper( object, hex ) { + return intersects; - 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 () { + /** + * 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. + */ - console.error( 'THREE.GridHelper: setColors() has been deprecated, pass them in the constructor instead.' ); + var Spherical = function Spherical( radius, phi, theta ) { + if ( radius === void 0 ) radius = 1; + if ( phi === void 0 ) phi = 0; + if ( theta === void 0 ) theta = 0; - }; - SkeletonHelper.prototype.update = function () { + this.radius = radius; + this.phi = phi; // polar angle + this.theta = theta; // azimuthal angle - console.error( 'THREE.SkeletonHelper: update() no longer needs to be called.' ); + return this; }; - function WireframeHelper( object, hex ) { + Spherical.prototype.set = function set ( radius, phi, theta ) { - 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 } ) ); + this.radius = radius; + this.phi = phi; + this.theta = theta; - } + return this; - // + }; - Object.assign( Loader.prototype, { + Spherical.prototype.clone = function clone () { - extractUrlBase: function ( url ) { + return new this.constructor().copy( this ); - console.warn( 'THREE.Loader: .extractUrlBase() has been deprecated. Use THREE.LoaderUtils.extractUrlBase() instead.' ); - return LoaderUtils.extractUrlBase( url ); + }; - } + Spherical.prototype.copy = function copy ( other ) { - } ); + this.radius = other.radius; + this.phi = other.phi; + this.theta = other.theta; - function XHRLoader( manager ) { + return this; - console.warn( 'THREE.XHRLoader has been renamed to THREE.FileLoader.' ); - return new FileLoader( manager ); + }; - } + // restrict phi to be betwee EPS and PI-EPS + Spherical.prototype.makeSafe = function makeSafe () { - function BinaryTextureLoader( manager ) { + var EPS = 0.000001; + this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); - console.warn( 'THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader.' ); - return new DataTextureLoader( manager ); + return this; - } + }; - Object.assign( JSONLoader.prototype, { + Spherical.prototype.setFromVector3 = function setFromVector3 ( v ) { - setTexturePath: function ( value ) { + return this.setFromCartesianCoords( v.x, v.y, v.z ); - console.warn( 'THREE.JSONLoader: .setTexturePath() has been renamed to .setResourcePath().' ); - return this.setResourcePath( value ); + }; - } + Spherical.prototype.setFromCartesianCoords = function setFromCartesianCoords ( x, y, z ) { - } ); + this.radius = Math.sqrt( x * x + y * y + z * z ); - Object.assign( ObjectLoader.prototype, { + if ( this.radius === 0 ) { - setTexturePath: function ( value ) { + this.theta = 0; + this.phi = 0; - console.warn( 'THREE.ObjectLoader: .setTexturePath() has been renamed to .setResourcePath().' ); - return this.setResourcePath( value ); + } else { - } + this.theta = Math.atan2( x, z ); + this.phi = Math.acos( MathUtils.clamp( y / this.radius, - 1, 1 ) ); - } ); + } - // + return this; - Object.assign( Box2.prototype, { + }; - center: function ( optionalTarget ) { + /** + * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system + */ - console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); + function Cylindrical( radius, theta, y ) { - }, - empty: function () { + this.radius = ( radius !== undefined ) ? radius : 1.0; // distance from the origin to a point in the x-z plane + this.theta = ( theta !== undefined ) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis + this.y = ( y !== undefined ) ? y : 0; // height above the x-z plane - console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); + return this; - }, - isIntersectionBox: function ( box ) { + } - console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); + Object.assign( Cylindrical.prototype, { - }, - size: function ( optionalTarget ) { + set: function ( radius, theta, y ) { - console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' ); - return this.getSize( optionalTarget ); + this.radius = radius; + this.theta = theta; + this.y = y; - } - } ); + return this; - Object.assign( Box3.prototype, { + }, - center: function ( optionalTarget ) { + clone: function () { - console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); + return new this.constructor().copy( this ); }, - empty: function () { - console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' ); - return this.isEmpty(); + copy: function ( other ) { - }, - isIntersectionBox: function ( box ) { + this.radius = other.radius; + this.theta = other.theta; + this.y = other.y; - console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); + return this; }, - isIntersectionSphere: function ( sphere ) { - console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); - return this.intersectsSphere( sphere ); + setFromVector3: function ( v ) { + + return this.setFromCartesianCoords( v.x, v.y, v.z ); }, - size: function ( optionalTarget ) { - console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' ); - return this.getSize( optionalTarget ); + setFromCartesianCoords: function ( x, y, z ) { + + this.radius = Math.sqrt( x * x + z * z ); + this.theta = Math.atan2( x, z ); + this.y = y; + + return this; } - } ); - Line3.prototype.center = function ( optionalTarget ) { + } ); - console.warn( 'THREE.Line3: .center() has been renamed to .getCenter().' ); - return this.getCenter( optionalTarget ); + var _vector$7 = new Vector2(); - }; + function Box2( min, max ) { - Object.assign( _Math, { + this.min = ( min !== undefined ) ? min : new Vector2( + Infinity, + Infinity ); + this.max = ( max !== undefined ) ? max : new Vector2( - Infinity, - Infinity ); - random16: function () { + } - console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' ); - return Math.random(); + Object.assign( Box2.prototype, { - }, + set: function ( min, max ) { - nearestPowerOfTwo: function ( value ) { + this.min.copy( min ); + this.max.copy( max ); - console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' ); - return _Math.floorPowerOfTwo( value ); + return this; }, - nextPowerOfTwo: function ( value ) { - - console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' ); - return _Math.ceilPowerOfTwo( value ); + setFromPoints: function ( points ) { - } + this.makeEmpty(); - } ); + for ( var i = 0, il = points.length; i < il; i ++ ) { - Object.assign( Matrix3.prototype, { + this.expandByPoint( points[ i ] ); - flattenToArrayOffset: function ( array, offset ) { + } - console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); - return this.toArray( array, offset ); + return this; }, - multiplyVector3: function ( vector ) { - console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); - return vector.applyMatrix3( this ); + setFromCenterAndSize: function ( center, size ) { - }, - multiplyVector3Array: function ( /* a */ ) { + var halfSize = _vector$7.copy( size ).multiplyScalar( 0.5 ); + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); - console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' ); + return this; }, - applyToBuffer: function ( buffer /*, offset, length */ ) { - console.warn( 'THREE.Matrix3: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); - return this.applyToBufferAttribute( buffer ); + clone: function () { - }, - applyToVector3Array: function ( /* array, offset, length */ ) { + return new this.constructor().copy( this ); - console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' ); + }, - } + copy: function ( box ) { - } ); + this.min.copy( box.min ); + this.max.copy( box.max ); - Object.assign( Matrix4.prototype, { + return this; - extractPosition: function ( m ) { + }, - console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); - return this.copyPosition( m ); + makeEmpty: function () { - }, - flattenToArrayOffset: function ( array, offset ) { + this.min.x = this.min.y = + Infinity; + this.max.x = this.max.y = - Infinity; - console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); - return this.toArray( array, offset ); + return this; }, - getPosition: function () { - var v1; + isEmpty: function () { + + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - return function getPosition() { + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); - if ( v1 === undefined ) v1 = new Vector3(); - console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); - return v1.setFromMatrixColumn( this, 3 ); + }, - }; + getCenter: function ( target ) { - }(), - setRotationFromQuaternion: function ( q ) { + if ( target === undefined ) { - console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); - return this.makeRotationFromQuaternion( q ); + console.warn( 'THREE.Box2: .getCenter() target is now required' ); + target = new Vector2(); - }, - multiplyToArray: function () { + } - console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' ); + return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); }, - multiplyVector3: function ( vector ) { - console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); + getSize: function ( target ) { - }, - multiplyVector4: function ( vector ) { + if ( target === undefined ) { - console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); + console.warn( 'THREE.Box2: .getSize() target is now required' ); + target = new Vector2(); - }, - multiplyVector3Array: function ( /* a */ ) { + } - console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' ); + return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); }, - rotateAxis: function ( v ) { - console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); - v.transformDirection( this ); + expandByPoint: function ( point ) { - }, - crossVector: function ( vector ) { + this.min.min( point ); + this.max.max( point ); - console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); - return vector.applyMatrix4( this ); + return this; }, - translate: function () { - console.error( 'THREE.Matrix4: .translate() has been removed.' ); + expandByVector: function ( vector ) { - }, - rotateX: function () { + this.min.sub( vector ); + this.max.add( vector ); - console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); + return this; }, - rotateY: function () { - console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); + expandByScalar: function ( scalar ) { - }, - rotateZ: function () { + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); - console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); + return this; }, - rotateByAxis: function () { - console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); + containsPoint: function ( point ) { + + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y ? false : true; }, - applyToBuffer: function ( buffer /*, offset, length */ ) { - console.warn( 'THREE.Matrix4: .applyToBuffer() has been removed. Use matrix.applyToBufferAttribute( attribute ) instead.' ); - return this.applyToBufferAttribute( buffer ); + containsBox: function ( 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; }, - applyToVector3Array: function ( /* array, offset, length */ ) { - console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' ); + getParameter: function ( point, target ) { - }, - makeFrustum: function ( left, right, bottom, top, near, far ) { + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - 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 ); + if ( target === undefined ) { - } + console.warn( 'THREE.Box2: .getParameter() target is now required' ); + target = new Vector2(); - } ); + } - Plane.prototype.isIntersectionLine = function ( line ) { + 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 ) + ); - console.warn( 'THREE.Plane: .isIntersectionLine() has been renamed to .intersectsLine().' ); - return this.intersectsLine( line ); + }, - }; + intersectsBox: function ( box ) { - Quaternion.prototype.multiplyVector3 = function ( vector ) { + // using 4 splitting planes to rule out intersections - console.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); - return vector.applyQuaternion( this ); + 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; - }; + }, - Object.assign( Ray.prototype, { + clampPoint: function ( point, target ) { - isIntersectionBox: function ( box ) { + if ( target === undefined ) { - console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' ); - return this.intersectsBox( box ); + console.warn( 'THREE.Box2: .clampPoint() target is now required' ); + target = new Vector2(); - }, - isIntersectionPlane: function ( plane ) { + } - console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' ); - return this.intersectsPlane( plane ); + return target.copy( point ).clamp( this.min, this.max ); }, - isIntersectionSphere: function ( sphere ) { - console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); - return this.intersectsSphere( sphere ); + distanceToPoint: function ( point ) { - } + var clampedPoint = _vector$7.copy( point ).clamp( this.min, this.max ); + return clampedPoint.sub( point ).length(); - } ); + }, - Object.assign( Triangle.prototype, { + intersect: function ( box ) { - area: function () { + this.min.max( box.min ); + this.max.min( box.max ); - console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' ); - return this.getArea(); + return this; }, - barycoordFromPoint: function ( point, target ) { - console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' ); - return this.getBarycoord( point, target ); + union: function ( box ) { - }, - midpoint: function ( target ) { + this.min.min( box.min ); + this.max.max( box.max ); - console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' ); - return this.getMidpoint( target ); + return this; }, - normal: function ( target ) { - console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' ); - return this.getNormal( target ); + translate: function ( offset ) { + + this.min.add( offset ); + this.max.add( offset ); + + return this; }, - plane: function ( target ) { - console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' ); - return this.getPlane( target ); + equals: function ( box ) { + + return box.min.equals( this.min ) && box.max.equals( this.max ); } } ); - Object.assign( Triangle, { + var _startP = new Vector3(); + var _startEnd = new Vector3(); - barycoordFromPoint: function ( point, a, b, c, target ) { + function Line3( start, end ) { - console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' ); - return Triangle.getBarycoord( point, a, b, c, target ); + this.start = ( start !== undefined ) ? start : new Vector3(); + this.end = ( end !== undefined ) ? end : new Vector3(); - }, - normal: function ( a, b, c, target ) { + } - console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' ); - return Triangle.getNormal( a, b, c, target ); + Object.assign( Line3.prototype, { - } + set: function ( start, end ) { - } ); + this.start.copy( start ); + this.end.copy( end ); - Object.assign( Shape.prototype, { - - extractAllPoints: function ( divisions ) { - - console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' ); - return this.extractPoints( divisions ); + return this; }, - extrude: function ( options ) { - console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' ); - return new ExtrudeGeometry( this, options ); + clone: function () { + + return new this.constructor().copy( this ); }, - makeGeometry: function ( options ) { - console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' ); - return new ShapeGeometry( this, options ); + copy: function ( line ) { - } + this.start.copy( line.start ); + this.end.copy( line.end ); - } ); + return this; - Object.assign( Vector2.prototype, { + }, - fromAttribute: function ( attribute, index, offset ) { + getCenter: function ( target ) { - console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); + if ( target === undefined ) { - }, - distanceToManhattan: function ( v ) { + console.warn( 'THREE.Line3: .getCenter() target is now required' ); + target = new Vector3(); - console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); - return this.manhattanDistanceTo( v ); + } - }, - lengthManhattan: function () { + return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); - console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); + }, - } + delta: function ( target ) { - } ); + if ( target === undefined ) { - Object.assign( Vector3.prototype, { + console.warn( 'THREE.Line3: .delta() target is now required' ); + target = new Vector3(); - setEulerFromRotationMatrix: function () { + } - console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); + return target.subVectors( this.end, this.start ); }, - setEulerFromQuaternion: function () { - - console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); - }, - getPositionFromMatrix: function ( m ) { + distanceSq: function () { - console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); - return this.setFromMatrixPosition( m ); + return this.start.distanceToSquared( this.end ); }, - getScaleFromMatrix: function ( m ) { - console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); - return this.setFromMatrixScale( m ); + distance: function () { + + return this.start.distanceTo( this.end ); }, - getColumnFromMatrix: function ( index, matrix ) { - console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); - return this.setFromMatrixColumn( matrix, index ); + at: function ( t, target ) { - }, - applyProjection: function ( m ) { + if ( target === undefined ) { - console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' ); - return this.applyMatrix4( m ); + console.warn( 'THREE.Line3: .at() target is now required' ); + target = new Vector3(); - }, - fromAttribute: function ( attribute, index, offset ) { + } - console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); + return this.delta( target ).multiplyScalar( t ).add( this.start ); }, - distanceToManhattan: function ( v ) { - console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); - return this.manhattanDistanceTo( v ); + closestPointToPointParameter: function ( point, clampToLine ) { - }, - lengthManhattan: function () { + _startP.subVectors( point, this.start ); + _startEnd.subVectors( this.end, this.start ); - console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); + var startEnd2 = _startEnd.dot( _startEnd ); + var startEnd_startP = _startEnd.dot( _startP ); - } + var t = startEnd_startP / startEnd2; - } ); + if ( clampToLine ) { - Object.assign( Vector4.prototype, { + t = MathUtils.clamp( t, 0, 1 ); - fromAttribute: function ( attribute, index, offset ) { + } - console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' ); - return this.fromBufferAttribute( attribute, index, offset ); + return t; }, - lengthManhattan: function () { - console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' ); - return this.manhattanLength(); + closestPointToPoint: function ( point, clampToLine, target ) { - } + var t = this.closestPointToPointParameter( point, clampToLine ); - } ); + if ( target === undefined ) { - // + console.warn( 'THREE.Line3: .closestPointToPoint() target is now required' ); + target = new Vector3(); - Object.assign( Geometry.prototype, { + } - computeTangents: function () { + return this.delta( target ).multiplyScalar( t ).add( this.start ); - console.error( 'THREE.Geometry: .computeTangents() has been removed.' ); + }, + + applyMatrix4: function ( matrix ) { + + this.start.applyMatrix4( matrix ); + this.end.applyMatrix4( matrix ); + + return this; }, - computeLineDistances: function () { - console.error( 'THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.' ); + equals: function ( line ) { + + return line.start.equals( this.start ) && line.end.equals( this.end ); } } ); - Object.assign( Object3D.prototype, { + function ImmediateRenderObject( material ) { - getChildByName: function ( name ) { + Object3D.call( this ); - console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); - return this.getObjectByName( name ); + this.material = material; + this.render = function ( /* renderCallback */ ) {}; - }, - renderDepth: function () { + this.hasPositions = false; + this.hasNormals = false; + this.hasColors = false; + this.hasUvs = false; - console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); + this.positionArray = null; + this.normalArray = null; + this.colorArray = null; + this.uvArray = null; - }, - translate: function ( distance, axis ) { + this.count = 0; - console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); - return this.translateOnAxis( axis, distance ); + } - }, - getWorldRotation: function () { + ImmediateRenderObject.prototype = Object.create( Object3D.prototype ); + ImmediateRenderObject.prototype.constructor = ImmediateRenderObject; - console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' ); + ImmediateRenderObject.prototype.isImmediateRenderObject = true; - } + var _vector$8 = new Vector3(); - } ); + function SpotLightHelper( light, color ) { - Object.defineProperties( Object3D.prototype, { + Object3D.call( this ); - eulerOrder: { - get: function () { + this.light = light; + this.light.updateMatrixWorld(); - console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); - return this.rotation.order; + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - }, - set: function ( value ) { + this.color = color; - console.warn( 'THREE.Object3D: .eulerOrder is now .rotation.order.' ); - this.rotation.order = value; + var geometry = new BufferGeometry(); - } - }, - useQuaternion: { - get: function () { + var 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 + ]; - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + for ( var i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { - }, - set: function () { + var p1 = ( i / l ) * Math.PI * 2; + var p2 = ( j / l ) * Math.PI * 2; - console.warn( 'THREE.Object3D: .useQuaternion has been removed. The library now uses quaternions by default.' ); + positions.push( + Math.cos( p1 ), Math.sin( p1 ), 1, + Math.cos( p2 ), Math.sin( p2 ), 1 + ); - } } - } ); + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - Object.defineProperties( LOD.prototype, { + var material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - objects: { - get: function () { + this.cone = new LineSegments( geometry, material ); + this.add( this.cone ); - console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); - return this.levels; + this.update(); - } - } + } - } ); + SpotLightHelper.prototype = Object.create( Object3D.prototype ); + SpotLightHelper.prototype.constructor = SpotLightHelper; - Object.defineProperty( Skeleton.prototype, 'useVertexTexture', { + SpotLightHelper.prototype.dispose = function () { - get: function () { + this.cone.geometry.dispose(); + this.cone.material.dispose(); - console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); + }; - }, - set: function () { + SpotLightHelper.prototype.update = function () { - console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); + this.light.updateMatrixWorld(); - } + var coneLength = this.light.distance ? this.light.distance : 1000; + var coneWidth = coneLength * Math.tan( this.light.angle ); - } ); + this.cone.scale.set( coneWidth, coneWidth, coneLength ); - Object.defineProperty( Curve.prototype, '__arcLengthDivisions', { + _vector$8.setFromMatrixPosition( this.light.target.matrixWorld ); - get: function () { + this.cone.lookAt( _vector$8 ); - console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); - return this.arcLengthDivisions; + if ( this.color !== undefined ) { - }, - set: function ( value ) { + this.cone.material.color.set( this.color ); - console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); - this.arcLengthDivisions = value; + } else { + + this.cone.material.color.copy( this.light.color ); } - } ); + }; - // + var _vector$9 = new Vector3(); + var _boneMatrix = new Matrix4(); + var _matrixWorldInv = new Matrix4(); - PerspectiveCamera.prototype.setLens = function ( focalLength, filmGauge ) { + function getBoneList( object ) { - console.warn( "THREE.PerspectiveCamera.setLens is deprecated. " + - "Use .setFocalLength and .filmGauge for a photographic setup." ); + var boneList = []; - if ( filmGauge !== undefined ) this.filmGauge = filmGauge; - this.setFocalLength( focalLength ); + if ( object && object.isBone ) { - }; + boneList.push( object ); - // + } - Object.defineProperties( Light.prototype, { - onlyShadow: { - set: function () { + for ( var i = 0; i < object.children.length; i ++ ) { - console.warn( 'THREE.Light: .onlyShadow has been removed.' ); + boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); - } - }, - shadowCameraFov: { - set: function ( value ) { + } - console.warn( 'THREE.Light: .shadowCameraFov is now .shadow.camera.fov.' ); - this.shadow.camera.fov = value; + return boneList; - } - }, - shadowCameraLeft: { - set: function ( value ) { + } - console.warn( 'THREE.Light: .shadowCameraLeft is now .shadow.camera.left.' ); - this.shadow.camera.left = value; + function SkeletonHelper( object ) { - } - }, - shadowCameraRight: { - set: function ( value ) { + var bones = getBoneList( object ); - console.warn( 'THREE.Light: .shadowCameraRight is now .shadow.camera.right.' ); - this.shadow.camera.right = value; + var geometry = new BufferGeometry(); - } - }, - shadowCameraTop: { - set: function ( value ) { + var vertices = []; + var colors = []; - console.warn( 'THREE.Light: .shadowCameraTop is now .shadow.camera.top.' ); - this.shadow.camera.top = value; + var color1 = new Color( 0, 0, 1 ); + var color2 = new Color( 0, 1, 0 ); - } - }, - shadowCameraBottom: { - set: function ( value ) { + for ( var i = 0; i < bones.length; i ++ ) { - console.warn( 'THREE.Light: .shadowCameraBottom is now .shadow.camera.bottom.' ); - this.shadow.camera.bottom = value; + var bone = bones[ i ]; - } - }, - shadowCameraNear: { - set: function ( value ) { + if ( bone.parent && bone.parent.isBone ) { - console.warn( 'THREE.Light: .shadowCameraNear is now .shadow.camera.near.' ); - this.shadow.camera.near = value; + 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 ); } - }, - shadowCameraFar: { - set: function ( value ) { - console.warn( 'THREE.Light: .shadowCameraFar is now .shadow.camera.far.' ); - this.shadow.camera.far = value; + } - } - }, - shadowCameraVisible: { - set: function () { + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - console.warn( 'THREE.Light: .shadowCameraVisible has been removed. Use new THREE.CameraHelper( light.shadow.camera ) instead.' ); + var material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); - } - }, - shadowBias: { - set: function ( value ) { + LineSegments.call( this, geometry, material ); - console.warn( 'THREE.Light: .shadowBias is now .shadow.bias.' ); - this.shadow.bias = value; + this.type = 'SkeletonHelper'; - } - }, - shadowDarkness: { - set: function () { + this.root = object; + this.bones = bones; - console.warn( 'THREE.Light: .shadowDarkness has been removed.' ); + this.matrix = object.matrixWorld; + this.matrixAutoUpdate = false; - } - }, - shadowMapWidth: { - set: function ( value ) { + } - console.warn( 'THREE.Light: .shadowMapWidth is now .shadow.mapSize.width.' ); - this.shadow.mapSize.width = value; + SkeletonHelper.prototype = Object.create( LineSegments.prototype ); + SkeletonHelper.prototype.constructor = SkeletonHelper; - } - }, - shadowMapHeight: { - set: function ( value ) { + SkeletonHelper.prototype.isSkeletonHelper = true; - console.warn( 'THREE.Light: .shadowMapHeight is now .shadow.mapSize.height.' ); - this.shadow.mapSize.height = value; + SkeletonHelper.prototype.updateMatrixWorld = function ( force ) { - } - } - } ); + var bones = this.bones; - // + var geometry = this.geometry; + var position = geometry.getAttribute( 'position' ); - Object.defineProperties( BufferAttribute.prototype, { + _matrixWorldInv.getInverse( this.root.matrixWorld ); - length: { - get: function () { + for ( var i = 0, j = 0; i < bones.length; i ++ ) { - console.warn( 'THREE.BufferAttribute: .length has been deprecated. Use .count instead.' ); - return this.array.length; + var bone = bones[ i ]; - } - }, - copyIndicesArray: function ( /* indices */ ) { + if ( bone.parent && bone.parent.isBone ) { - console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' ); + _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); + _vector$9.setFromMatrixPosition( _boneMatrix ); + position.setXYZ( j, _vector$9.x, _vector$9.y, _vector$9.z ); - } + _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); + _vector$9.setFromMatrixPosition( _boneMatrix ); + position.setXYZ( j + 1, _vector$9.x, _vector$9.y, _vector$9.z ); - } ); + j += 2; - Object.assign( BufferGeometry.prototype, { + } - addIndex: function ( index ) { + } - console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); - this.setIndex( index ); + geometry.getAttribute( 'position' ).needsUpdate = true; - }, - addDrawCall: function ( start, count, indexOffset ) { + Object3D.prototype.updateMatrixWorld.call( this, force ); - if ( indexOffset !== undefined ) { + }; - console.warn( 'THREE.BufferGeometry: .addDrawCall() no longer supports indexOffset.' ); + function PointLightHelper( light, sphereSize, color ) { - } - console.warn( 'THREE.BufferGeometry: .addDrawCall() is now .addGroup().' ); - this.addGroup( start, count ); + this.light = light; + this.light.updateMatrixWorld(); - }, - clearDrawCalls: function () { + this.color = color; - console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); - this.clearGroups(); + var geometry = new SphereBufferGeometry( sphereSize, 4, 2 ); + var material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); - }, - computeTangents: function () { + Mesh.call( this, geometry, material ); - console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); + this.type = 'PointLightHelper'; - }, - computeOffsets: function () { + this.matrix = this.light.matrixWorld; + this.matrixAutoUpdate = false; - console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' ); + this.update(); - } - } ); + /* + const distanceGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 ); + const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); - Object.defineProperties( BufferGeometry.prototype, { + this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); + this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); - drawcalls: { - get: function () { + const d = light.distance; - console.error( 'THREE.BufferGeometry: .drawcalls has been renamed to .groups.' ); - return this.groups; + if ( d === 0.0 ) { - } - }, - offsets: { - get: function () { + this.lightDistance.visible = false; - console.warn( 'THREE.BufferGeometry: .offsets has been renamed to .groups.' ); - return this.groups; + } else { + + this.lightDistance.scale.set( d, d, d ); - } } - } ); + this.add( this.lightDistance ); + */ - // + } - Object.assign( ExtrudeBufferGeometry.prototype, { + PointLightHelper.prototype = Object.create( Mesh.prototype ); + PointLightHelper.prototype.constructor = PointLightHelper; - getArrays: function () { + PointLightHelper.prototype.dispose = function () { - console.error( 'THREE.ExtrudeBufferGeometry: .getArrays() has been removed.' ); + this.geometry.dispose(); + this.material.dispose(); - }, + }; - addShapeList: function () { + PointLightHelper.prototype.update = function () { - console.error( 'THREE.ExtrudeBufferGeometry: .addShapeList() has been removed.' ); + if ( this.color !== undefined ) { - }, + this.material.color.set( this.color ); - addShape: function () { + } else { - console.error( 'THREE.ExtrudeBufferGeometry: .addShape() has been removed.' ); + this.material.color.copy( this.light.color ); } - } ); - - // - - Object.defineProperties( Uniform.prototype, { + /* + const d = this.light.distance; - dynamic: { - set: function () { + if ( d === 0.0 ) { - console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' ); + this.lightDistance.visible = false; - } - }, - onUpdate: { - value: function () { + } else { - console.warn( 'THREE.Uniform: .onUpdate() has been removed. Use object.onBeforeRender() instead.' ); - return this; + this.lightDistance.visible = true; + this.lightDistance.scale.set( d, d, d ); - } } + */ - } ); + }; - // + var _vector$a = new Vector3(); + var _color1 = new Color(); + var _color2 = new Color(); - Object.defineProperties( Material.prototype, { + function HemisphereLightHelper( light, size, color ) { - wrapAround: { - get: function () { + Object3D.call( this ); - console.warn( 'THREE.Material: .wrapAround has been removed.' ); + this.light = light; + this.light.updateMatrixWorld(); - }, - set: function () { + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - console.warn( 'THREE.Material: .wrapAround has been removed.' ); + this.color = color; - } - }, + var geometry = new OctahedronBufferGeometry( size ); + geometry.rotateY( Math.PI * 0.5 ); - overdraw: { - get: function () { + this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); + if ( this.color === undefined ) { this.material.vertexColors = true; } - console.warn( 'THREE.Material: .overdraw has been removed.' ); + var position = geometry.getAttribute( 'position' ); + var colors = new Float32Array( position.count * 3 ); - }, - set: function () { + geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); - console.warn( 'THREE.Material: .overdraw has been removed.' ); + this.add( new Mesh( geometry, this.material ) ); - } - }, + this.update(); - wrapRGB: { - get: function () { + } - console.warn( 'THREE.Material: .wrapRGB has been removed.' ); - return new Color(); + HemisphereLightHelper.prototype = Object.create( Object3D.prototype ); + HemisphereLightHelper.prototype.constructor = HemisphereLightHelper; - } - }, + HemisphereLightHelper.prototype.dispose = function () { - shading: { - get: function () { + this.children[ 0 ].geometry.dispose(); + this.children[ 0 ].material.dispose(); - console.error( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); + }; - }, - set: function ( value ) { + HemisphereLightHelper.prototype.update = function () { - console.warn( 'THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.' ); - this.flatShading = ( value === FlatShading ); + var mesh = this.children[ 0 ]; - } - } + if ( this.color !== undefined ) { - } ); + this.material.color.set( this.color ); - Object.defineProperties( MeshPhongMaterial.prototype, { + } else { - metal: { - get: function () { + var colors = mesh.geometry.getAttribute( 'color' ); - console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' ); - return false; + _color1.copy( this.light.color ); + _color2.copy( this.light.groundColor ); - }, - set: function () { + for ( var i = 0, l = colors.count; i < l; i ++ ) { - console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' ); + var color = ( i < ( l / 2 ) ) ? _color1 : _color2; + + colors.setXYZ( i, color.r, color.g, color.b ); } - } - } ); + colors.needsUpdate = true; - Object.defineProperties( ShaderMaterial.prototype, { + } - derivatives: { - get: function () { + mesh.lookAt( _vector$a.setFromMatrixPosition( this.light.matrixWorld ).negate() ); - console.warn( 'THREE.ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); - return this.extensions.derivatives; + }; - }, - set: function ( value ) { + function GridHelper( size, divisions, color1, color2 ) { - console.warn( 'THREE. ShaderMaterial: .derivatives has been moved to .extensions.derivatives.' ); - this.extensions.derivatives = value; + size = size || 10; + divisions = divisions || 10; + color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); + color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); - } - } + var center = divisions / 2; + var step = size / divisions; + var halfSize = size / 2; - } ); + var vertices = [], colors = []; - // + for ( var i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { - Object.assign( WebGLRenderer.prototype, { + vertices.push( - halfSize, 0, k, halfSize, 0, k ); + vertices.push( k, 0, - halfSize, k, 0, halfSize ); - clearTarget: function ( renderTarget, color, depth, stencil ) { + var color = i === center ? color1 : color2; - console.warn( 'THREE.WebGLRenderer: .clearTarget() has been deprecated. Use .setRenderTarget() and .clear() instead.' ); - this.setRenderTarget( renderTarget ); - this.clear( color, depth, stencil ); + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; + color.toArray( colors, j ); j += 3; - }, + } - animate: function ( callback ) { + var geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' ); - this.setAnimationLoop( callback ); + var material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - }, + LineSegments.call( this, geometry, material ); - getCurrentRenderTarget: function () { + this.type = 'GridHelper'; - console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' ); - return this.getRenderTarget(); + } - }, + GridHelper.prototype = Object.create( LineSegments.prototype ); + GridHelper.prototype.constructor = GridHelper; - getMaxAnisotropy: function () { + function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) { - console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' ); - return this.capabilities.getMaxAnisotropy(); + radius = radius || 10; + radials = radials || 16; + circles = circles || 8; + divisions = divisions || 64; + color1 = new Color( color1 !== undefined ? color1 : 0x444444 ); + color2 = new Color( color2 !== undefined ? color2 : 0x888888 ); - }, + var vertices = []; + var colors = []; - getPrecision: function () { + // create the radials - console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' ); - return this.capabilities.precision; + for ( var i = 0; i <= radials; i ++ ) { - }, + var v = ( i / radials ) * ( Math.PI * 2 ); - resetGLState: function () { + var x = Math.sin( v ) * radius; + var z = Math.cos( v ) * radius; - console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' ); - return this.state.reset(); + vertices.push( 0, 0, 0 ); + vertices.push( x, 0, z ); - }, + var color = ( i & 1 ) ? color1 : color2; - supportsFloatTextures: function () { + colors.push( color.r, color.g, color.b ); + colors.push( color.r, color.g, color.b ); - console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); - return this.extensions.get( 'OES_texture_float' ); + } - }, - supportsHalfFloatTextures: function () { + // create the circles - console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); - return this.extensions.get( 'OES_texture_half_float' ); + for ( var i$1 = 0; i$1 <= circles; i$1 ++ ) { - }, - supportsStandardDerivatives: function () { + var color$1 = ( i$1 & 1 ) ? color1 : color2; - console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); - return this.extensions.get( 'OES_standard_derivatives' ); + var r = radius - ( radius / circles * i$1 ); - }, - supportsCompressedTextureS3TC: function () { + for ( var j = 0; j < divisions; j ++ ) { - console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); - return this.extensions.get( 'WEBGL_compressed_texture_s3tc' ); + // first vertex - }, - supportsCompressedTexturePVRTC: function () { + var v$1 = ( j / divisions ) * ( Math.PI * 2 ); - console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); - return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + var x$1 = Math.sin( v$1 ) * r; + var z$1 = Math.cos( v$1 ) * r; - }, - supportsBlendMinMax: function () { + vertices.push( x$1, 0, z$1 ); + colors.push( color$1.r, color$1.g, color$1.b ); - console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); - return this.extensions.get( 'EXT_blend_minmax' ); + // second vertex - }, - supportsVertexTextures: function () { + v$1 = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); - console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' ); - return this.capabilities.vertexTextures; + x$1 = Math.sin( v$1 ) * r; + z$1 = Math.cos( v$1 ) * r; - }, - supportsInstancedArrays: function () { + vertices.push( x$1, 0, z$1 ); + colors.push( color$1.r, color$1.g, color$1.b ); - console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); - return this.extensions.get( 'ANGLE_instanced_arrays' ); + } - }, - enableScissorTest: function ( boolean ) { + } - console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' ); - this.setScissorTest( boolean ); + var geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - }, - initMaterial: function () { + var material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); - console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); + LineSegments.call( this, geometry, material ); - }, - addPrePlugin: function () { + this.type = 'PolarGridHelper'; - console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); + } - }, - addPostPlugin: function () { + PolarGridHelper.prototype = Object.create( LineSegments.prototype ); + PolarGridHelper.prototype.constructor = PolarGridHelper; - console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); + var _v1$5 = new Vector3(); + var _v2$3 = new Vector3(); + var _v3$1 = new Vector3(); - }, - updateShadowMap: function () { + function DirectionalLightHelper( light, size, color ) { - console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); + Object3D.call( this ); - }, - setFaceCulling: function () { + this.light = light; + this.light.updateMatrixWorld(); - console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' ); + this.matrix = light.matrixWorld; + this.matrixAutoUpdate = false; - } + this.color = color; - } ); + if ( size === undefined ) { size = 1; } - Object.defineProperties( WebGLRenderer.prototype, { + var geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( [ + - size, size, 0, + size, size, 0, + size, - size, 0, + - size, - size, 0, + - size, size, 0 + ], 3 ) ); - shadowMapEnabled: { - get: function () { + var material = new LineBasicMaterial( { fog: false, toneMapped: false } ); - return this.shadowMap.enabled; + this.lightPlane = new Line( geometry, material ); + this.add( this.lightPlane ); - }, - set: function ( value ) { + geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); - console.warn( 'THREE.WebGLRenderer: .shadowMapEnabled is now .shadowMap.enabled.' ); - this.shadowMap.enabled = value; + this.targetLine = new Line( geometry, material ); + this.add( this.targetLine ); - } - }, - shadowMapType: { - get: function () { + this.update(); - return this.shadowMap.type; + } - }, - set: function ( value ) { + DirectionalLightHelper.prototype = Object.create( Object3D.prototype ); + DirectionalLightHelper.prototype.constructor = DirectionalLightHelper; - console.warn( 'THREE.WebGLRenderer: .shadowMapType is now .shadowMap.type.' ); - this.shadowMap.type = value; + DirectionalLightHelper.prototype.dispose = function () { - } - }, - shadowMapCullFace: { - get: function () { + this.lightPlane.geometry.dispose(); + this.lightPlane.material.dispose(); + this.targetLine.geometry.dispose(); + this.targetLine.material.dispose(); - console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' ); - return undefined; + }; - }, - set: function ( /* value */ ) { + DirectionalLightHelper.prototype.update = function () { - console.warn( 'THREE.WebGLRenderer: .shadowMapCullFace has been removed. Set Material.shadowSide instead.' ); + _v1$5.setFromMatrixPosition( this.light.matrixWorld ); + _v2$3.setFromMatrixPosition( this.light.target.matrixWorld ); + _v3$1.subVectors( _v2$3, _v1$5 ); - } - } - } ); + this.lightPlane.lookAt( _v2$3 ); - Object.defineProperties( WebGLShadowMap.prototype, { + if ( this.color !== undefined ) { - cullFace: { - get: function () { + this.lightPlane.material.color.set( this.color ); + this.targetLine.material.color.set( this.color ); - console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' ); - return undefined; + } else { - }, - set: function ( /* cullFace */ ) { + this.lightPlane.material.color.copy( this.light.color ); + this.targetLine.material.color.copy( this.light.color ); - console.warn( 'THREE.WebGLRenderer: .shadowMap.cullFace has been removed. Set Material.shadowSide instead.' ); + } - } - }, - renderReverseSided: { - get: function () { + this.targetLine.lookAt( _v2$3 ); + this.targetLine.scale.z = _v3$1.length(); - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' ); - return undefined; + }; - }, - set: function () { + var _vector$b = new Vector3(); + var _camera = new Camera(); - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderReverseSided has been removed. Set Material.shadowSide instead.' ); + /** + * - 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 + */ - } - }, - renderSingleSided: { - get: function () { + function CameraHelper( camera ) { - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' ); - return undefined; + var geometry = new BufferGeometry(); + var material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); - }, - set: function () { + var vertices = []; + var colors = []; - console.warn( 'THREE.WebGLRenderer: .shadowMap.renderSingleSided has been removed. Set Material.shadowSide instead.' ); + var pointMap = {}; - } - } + // colors - } ); + var colorFrustum = new Color( 0xffaa00 ); + var colorCone = new Color( 0xff0000 ); + var colorUp = new Color( 0x00aaff ); + var colorTarget = new Color( 0xffffff ); + var colorCross = new Color( 0x333333 ); - // + // near - Object.defineProperties( WebGLRenderTarget.prototype, { + addLine( 'n1', 'n2', colorFrustum ); + addLine( 'n2', 'n4', colorFrustum ); + addLine( 'n4', 'n3', colorFrustum ); + addLine( 'n3', 'n1', colorFrustum ); - wrapS: { - get: function () { + // far - console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); - return this.texture.wrapS; + addLine( 'f1', 'f2', colorFrustum ); + addLine( 'f2', 'f4', colorFrustum ); + addLine( 'f4', 'f3', colorFrustum ); + addLine( 'f3', 'f1', colorFrustum ); - }, - set: function ( value ) { + // sides - console.warn( 'THREE.WebGLRenderTarget: .wrapS is now .texture.wrapS.' ); - this.texture.wrapS = value; + addLine( 'n1', 'f1', colorFrustum ); + addLine( 'n2', 'f2', colorFrustum ); + addLine( 'n3', 'f3', colorFrustum ); + addLine( 'n4', 'f4', colorFrustum ); - } - }, - wrapT: { - get: function () { + // cone - console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); - return this.texture.wrapT; + addLine( 'p', 'n1', colorCone ); + addLine( 'p', 'n2', colorCone ); + addLine( 'p', 'n3', colorCone ); + addLine( 'p', 'n4', colorCone ); - }, - set: function ( value ) { + // up - console.warn( 'THREE.WebGLRenderTarget: .wrapT is now .texture.wrapT.' ); - this.texture.wrapT = value; + addLine( 'u1', 'u2', colorUp ); + addLine( 'u2', 'u3', colorUp ); + addLine( 'u3', 'u1', colorUp ); - } - }, - magFilter: { - get: function () { + // target - console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); - return this.texture.magFilter; + addLine( 'c', 't', colorTarget ); + addLine( 'p', 'c', colorCross ); - }, - set: function ( value ) { + // cross - console.warn( 'THREE.WebGLRenderTarget: .magFilter is now .texture.magFilter.' ); - this.texture.magFilter = value; + addLine( 'cn1', 'cn2', colorCross ); + addLine( 'cn3', 'cn4', colorCross ); - } - }, - minFilter: { - get: function () { + addLine( 'cf1', 'cf2', colorCross ); + addLine( 'cf3', 'cf4', colorCross ); - console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); - return this.texture.minFilter; + function addLine( a, b, color ) { - }, - set: function ( value ) { + addPoint( a, color ); + addPoint( b, color ); - console.warn( 'THREE.WebGLRenderTarget: .minFilter is now .texture.minFilter.' ); - this.texture.minFilter = value; + } - } - }, - anisotropy: { - get: function () { + function addPoint( id, color ) { - console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); - return this.texture.anisotropy; + vertices.push( 0, 0, 0 ); + colors.push( color.r, color.g, color.b ); - }, - set: function ( value ) { + if ( pointMap[ id ] === undefined ) { - console.warn( 'THREE.WebGLRenderTarget: .anisotropy is now .texture.anisotropy.' ); - this.texture.anisotropy = value; + pointMap[ id ] = []; } - }, - offset: { - get: function () { - console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); - return this.texture.offset; + pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); - }, - set: function ( value ) { + } - console.warn( 'THREE.WebGLRenderTarget: .offset is now .texture.offset.' ); - this.texture.offset = value; + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); - } - }, - repeat: { - get: function () { + LineSegments.call( this, geometry, material ); - console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); - return this.texture.repeat; + this.type = 'CameraHelper'; - }, - set: function ( value ) { + this.camera = camera; + if ( this.camera.updateProjectionMatrix ) { this.camera.updateProjectionMatrix(); } - console.warn( 'THREE.WebGLRenderTarget: .repeat is now .texture.repeat.' ); - this.texture.repeat = value; + this.matrix = camera.matrixWorld; + this.matrixAutoUpdate = false; - } - }, - format: { - get: function () { + this.pointMap = pointMap; - console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); - return this.texture.format; + this.update(); - }, - set: function ( value ) { + } - console.warn( 'THREE.WebGLRenderTarget: .format is now .texture.format.' ); - this.texture.format = value; + CameraHelper.prototype = Object.create( LineSegments.prototype ); + CameraHelper.prototype.constructor = CameraHelper; - } - }, - type: { - get: function () { + CameraHelper.prototype.update = function () { - console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); - return this.texture.type; + var geometry = this.geometry; + var pointMap = this.pointMap; - }, - set: function ( value ) { + var w = 1, h = 1; - console.warn( 'THREE.WebGLRenderTarget: .type is now .texture.type.' ); - this.texture.type = value; + // we need just camera projection matrix inverse + // world matrix must be identity - } - }, - generateMipmaps: { - get: function () { + _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); - console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); - return this.texture.generateMipmaps; + // center / target - }, - set: function ( value ) { + setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); + setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); - console.warn( 'THREE.WebGLRenderTarget: .generateMipmaps is now .texture.generateMipmaps.' ); - this.texture.generateMipmaps = value; + // 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 ); - Object.defineProperties( WebVRManager.prototype, { + // up - standing: { - set: function ( /* value */ ) { + 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 ); - console.warn( 'THREE.WebVRManager: .standing has been removed.' ); + // cross - } - }, - userHeight: { - set: function ( /* value */ ) { + 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 ); - console.warn( 'THREE.WebVRManager: .userHeight has been removed.' ); + 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; - } ); + }; - // + function setPoint( point, pointMap, geometry, camera, x, y, z ) { - Audio.prototype.load = function ( file ) { + _vector$b.set( x, y, z ).unproject( camera ); - console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' ); - var scope = this; - var audioLoader = new AudioLoader(); - audioLoader.load( file, function ( buffer ) { + var points = pointMap[ point ]; - scope.setBuffer( buffer ); + if ( points !== undefined ) { - } ); - return this; + var position = geometry.getAttribute( 'position' ); - }; + for ( var i = 0, l = points.length; i < l; i ++ ) { - AudioAnalyser.prototype.getData = function () { + position.setXYZ( points[ i ], _vector$b.x, _vector$b.y, _vector$b.z ); - console.warn( 'THREE.AudioAnalyser: .getData() is now .getFrequencyData().' ); - return this.getFrequencyData(); + } - }; + } - // + } - CubeCamera.prototype.updateCubeMap = function ( renderer, scene ) { + var _box$3 = new Box3(); - console.warn( 'THREE.CubeCamera: .updateCubeMap() is now .update().' ); - return this.update( renderer, scene ); + function BoxHelper( object, color ) { - }; + this.object = object; - // + if ( color === undefined ) { color = 0xffff00; } - var GeometryUtils = { + var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + var positions = new Float32Array( 8 * 3 ); - merge: function ( geometry1, geometry2, materialIndexOffset ) { + var geometry = new BufferGeometry(); + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); - console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); - var matrix; + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - if ( geometry2.isMesh ) { + this.type = 'BoxHelper'; - geometry2.matrixAutoUpdate && geometry2.updateMatrix(); + this.matrixAutoUpdate = false; - matrix = geometry2.matrix; - geometry2 = geometry2.geometry; + this.update(); - } + } - geometry1.merge( geometry2, matrix, materialIndexOffset ); + BoxHelper.prototype = Object.create( LineSegments.prototype ); + BoxHelper.prototype.constructor = BoxHelper; - }, + BoxHelper.prototype.update = function ( object ) { - center: function ( geometry ) { + if ( object !== undefined ) { - console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); - return geometry.center(); + console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); } - }; + if ( this.object !== undefined ) { - ImageUtils.crossOrigin = undefined; + _box$3.setFromObject( this.object ); - ImageUtils.loadTexture = function ( url, mapping, onLoad, onError ) { + } - console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' ); + if ( _box$3.isEmpty() ) { return; } - var loader = new TextureLoader(); - loader.setCrossOrigin( this.crossOrigin ); + var min = _box$3.min; + var max = _box$3.max; - var texture = loader.load( url, onLoad, undefined, onError ); + /* + 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 + */ - if ( mapping ) texture.mapping = mapping; + var position = this.geometry.attributes.position; + var array = position.array; - return texture; + 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; - ImageUtils.loadTextureCube = function ( urls, mapping, onLoad, onError ) { + this.geometry.computeBoundingSphere(); - console.warn( 'THREE.ImageUtils.loadTextureCube has been deprecated. Use THREE.CubeTextureLoader() instead.' ); - var loader = new CubeTextureLoader(); - loader.setCrossOrigin( this.crossOrigin ); + }; - var texture = loader.load( urls, onLoad, undefined, onError ); + BoxHelper.prototype.setFromObject = function ( object ) { - if ( mapping ) texture.mapping = mapping; + this.object = object; + this.update(); - return texture; + return this; }; - ImageUtils.loadCompressedTexture = function () { + BoxHelper.prototype.copy = function ( source ) { - console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' ); + LineSegments.prototype.copy.call( this, source ); + + this.object = source.object; + + return this; }; - ImageUtils.loadCompressedTextureCube = function () { + function Box3Helper( box, color ) { - console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' ); + this.type = 'Box3Helper'; + + this.box = box; + + if ( color === undefined ) { color = 0xffff00; } + + var indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); + + var 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 ]; + + var geometry = new BufferGeometry(); + + geometry.setIndex( new BufferAttribute( indices, 1 ) ); + + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + + LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); + + this.type = 'Box3Helper'; + + this.geometry.computeBoundingSphere(); + + } + + Box3Helper.prototype = Object.create( LineSegments.prototype ); + Box3Helper.prototype.constructor = Box3Helper; + + Box3Helper.prototype.updateMatrixWorld = function ( force ) { + + var box = this.box; + + if ( box.isEmpty() ) { return; } + + box.getCenter( this.position ); + + box.getSize( this.scale ); + + this.scale.multiplyScalar( 0.5 ); + + Object3D.prototype.updateMatrixWorld.call( this, force ); }; - // + function PlaneHelper( plane, size, hex ) { - function Projector() { + this.plane = plane; - console.error( 'THREE.Projector has been moved to /examples/js/renderers/Projector.js.' ); + this.size = ( size === undefined ) ? 1 : size; - this.projectVector = function ( vector, camera ) { + var color = ( hex !== undefined ) ? hex : 0xffff00; - console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); - vector.project( camera ); + var 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 ]; - }; + var geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + geometry.computeBoundingSphere(); - this.unprojectVector = function ( vector, camera ) { + Line.call( this, geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); - console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); - vector.unproject( camera ); + this.type = 'PlaneHelper'; - }; + // - this.pickingRay = function () { + var positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ]; - console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); + var 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 } ) ) ); } - // + PlaneHelper.prototype = Object.create( Line.prototype ); + PlaneHelper.prototype.constructor = PlaneHelper; - function CanvasRenderer() { + PlaneHelper.prototype.updateMatrixWorld = function ( force ) { - console.error( 'THREE.CanvasRenderer has been removed' ); + var 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 ); + + Object3D.prototype.updateMatrixWorld.call( this, force ); + + }; + + var _axis = new Vector3(); + var _lineGeometry, _coneGeometry; + + function ArrowHelper( dir, origin, length, color, headLength, headWidth ) { + + // dir is assumed to be normalized + + Object3D.call( this ); + + this.type = 'ArrowHelper'; + + if ( dir === undefined ) { dir = new Vector3( 0, 0, 1 ); } + if ( origin === undefined ) { origin = new Vector3( 0, 0, 0 ); } + if ( length === undefined ) { length = 1; } + if ( color === undefined ) { color = 0xffff00; } + if ( headLength === undefined ) { headLength = 0.2 * length; } + if ( headWidth === undefined ) { headWidth = 0.2 * headLength; } + + if ( _lineGeometry === undefined ) { + + _lineGeometry = new BufferGeometry(); + _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); + + _coneGeometry = new CylinderBufferGeometry( 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 ); } - // + ArrowHelper.prototype = Object.create( Object3D.prototype ); + ArrowHelper.prototype.constructor = ArrowHelper; - var SceneUtils = { + ArrowHelper.prototype.setDirection = function ( dir ) { - createMultiMaterialObject: function ( /* geometry, materials */ ) { + // 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(); + + var radians = Math.acos( dir.y ); + + this.quaternion.setFromAxisAngle( _axis, radians ); + + } + + }; + + ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { + + if ( headLength === undefined ) { headLength = 0.2 * length; } + if ( headWidth === undefined ) { headWidth = 0.2 * headLength; } + + this.line.scale.set( 1, 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(); + + }; + + ArrowHelper.prototype.setColor = function ( color ) { + + this.line.material.color.set( color ); + this.cone.material.color.set( color ); + + }; + + ArrowHelper.prototype.copy = function ( source ) { + + Object3D.prototype.copy.call( this, source, false ); + + this.line.copy( source.line ); + this.cone.copy( source.cone ); + + return this; + + }; + + function AxesHelper( size ) { + + size = size || 1; + + var vertices = [ + 0, 0, 0, size, 0, 0, + 0, 0, 0, 0, size, 0, + 0, 0, 0, 0, 0, size + ]; + + var colors = [ + 1, 0, 0, 1, 0.6, 0, + 0, 1, 0, 0.6, 1, 0, + 0, 0, 1, 0, 0.6, 1 + ]; + + var geometry = new BufferGeometry(); + geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); + + var material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); + + LineSegments.call( this, geometry, material ); + + this.type = 'AxesHelper'; + + } + + AxesHelper.prototype = Object.create( LineSegments.prototype ); + AxesHelper.prototype.constructor = AxesHelper; + + var LOD_MIN = 4; + var LOD_MAX = 8; + var 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. + var EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; + + var 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. + var MAX_SAMPLES = 20; + + var ENCODINGS = {}; + ENCODINGS[ LinearEncoding ] = 0; + ENCODINGS[ sRGBEncoding ] = 1; + ENCODINGS[ RGBEEncoding ] = 2; + ENCODINGS[ RGBM7Encoding ] = 3; + ENCODINGS[ RGBM16Encoding ] = 4; + ENCODINGS[ RGBDEncoding ] = 5; + ENCODINGS[ GammaEncoding ] = 6; + + var _flatCamera = new OrthographicCamera(); + var ref = _createPlanes(); + var _lodPlanes = ref._lodPlanes; + var _sizeLods = ref._sizeLods; + var _sigmas = ref._sigmas; + var _oldTarget = null; + + // Golden Ratio + var PHI = ( 1 + Math.sqrt( 5 ) ) / 2; + var 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. + var _axisDirections = [ + new Vector3( 1, 1, 1 ), + new Vector3( - 1, 1, 1 ), + new Vector3( 1, 1, - 1 ), + new Vector3( - 1, 1, - 1 ), + new Vector3( 0, PHI, INV_PHI ), + new Vector3( 0, PHI, - INV_PHI ), + new Vector3( INV_PHI, 0, PHI ), + new Vector3( - INV_PHI, 0, PHI ), + new Vector3( PHI, INV_PHI, 0 ), + 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. + */ + + function PMREMGenerator( renderer ) { + + this._renderer = renderer; + this._pingPongRenderTarget = null; + + this._blurMaterial = _getBlurShader( MAX_SAMPLES ); + this._equirectShader = null; + this._cubemapShader = null; + + this._compileMaterial( this._blurMaterial ); + + } + + PMREMGenerator.prototype = { + + constructor: PMREMGenerator, + + /** + * 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: function ( scene, sigma, near, far ) { + if ( sigma === void 0 ) sigma = 0; + if ( near === void 0 ) near = 0.1; + if ( far === void 0 ) far = 100; + + + _oldTarget = this._renderer.getRenderTarget(); + var cubeUVRenderTarget = this._allocateTargets(); - console.error( 'THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js' ); + this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); + if ( sigma > 0 ) { + + this._blur( cubeUVRenderTarget, 0, 0, sigma ); + + } + + this._applyPMREM( cubeUVRenderTarget ); + this._cleanup( cubeUVRenderTarget ); + + return cubeUVRenderTarget; }, - detach: function ( /* child, parent, scene */ ) { + /** + * 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: function ( equirectangular ) { - console.error( 'THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js' ); + return this._fromTexture( equirectangular ); }, - attach: function ( /* child, scene, parent */ ) { + /** + * 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: function ( 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: function () { + + 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: function () { + + 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: function () { + + this._blurMaterial.dispose(); + + if ( this._cubemapShader !== null ) { this._cubemapShader.dispose(); } + if ( this._equirectShader !== null ) { this._equirectShader.dispose(); } + + for ( var i = 0; i < _lodPlanes.length; i ++ ) { + + _lodPlanes[ i ].dispose(); + + } + + }, + + // private interface + + _cleanup: function ( outputTarget ) { + + this._pingPongRenderTarget.dispose(); + this._renderer.setRenderTarget( _oldTarget ); + outputTarget.scissorTest = false; + _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); + + }, + + _fromTexture: function ( texture ) { + + _oldTarget = this._renderer.getRenderTarget(); + var cubeUVRenderTarget = this._allocateTargets( texture ); + this._textureToCubeUV( texture, cubeUVRenderTarget ); + this._applyPMREM( cubeUVRenderTarget ); + this._cleanup( cubeUVRenderTarget ); + + return cubeUVRenderTarget; + + }, + + _allocateTargets: function ( texture ) { // warning: null texture is valid + + var params = { + magFilter: NearestFilter, + minFilter: NearestFilter, + generateMipmaps: false, + type: UnsignedByteType, + format: RGBEFormat, + encoding: _isLDR( texture ) ? texture.encoding : RGBEEncoding, + depthBuffer: false, + stencilBuffer: false + }; + + var cubeUVRenderTarget = _createRenderTarget( params ); + cubeUVRenderTarget.depthBuffer = texture ? false : true; + this._pingPongRenderTarget = _createRenderTarget( params ); + return cubeUVRenderTarget; + + }, + + _compileMaterial: function ( material ) { + + var tmpMesh = new Mesh( _lodPlanes[ 0 ], material ); + this._renderer.compile( tmpMesh, _flatCamera ); + + }, + + _sceneToCubeUV: function ( scene, near, far, cubeUVRenderTarget ) { + + var fov = 90; + var aspect = 1; + var cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); + var upSign = [ 1, - 1, 1, 1, 1, 1 ]; + var forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; + var renderer = this._renderer; + + var outputEncoding = renderer.outputEncoding; + var toneMapping = renderer.toneMapping; + var clearColor = renderer.getClearColor(); + var clearAlpha = renderer.getClearAlpha(); + + renderer.toneMapping = NoToneMapping; + renderer.outputEncoding = LinearEncoding; + + var background = scene.background; + if ( background && background.isColor ) { + + background.convertSRGBToLinear(); + // Convert linear to RGBE + var maxComponent = Math.max( background.r, background.g, background.b ); + var fExp = Math.min( Math.max( Math.ceil( Math.log2( maxComponent ) ), - 128.0 ), 127.0 ); + background = background.multiplyScalar( Math.pow( 2.0, - fExp ) ); + var alpha = ( fExp + 128.0 ) / 255.0; + renderer.setClearColor( background, alpha ); + scene.background = null; + + } + + for ( var i = 0; i < 6; i ++ ) { + + var 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 ); + renderer.render( scene, cubeCamera ); + + } + + renderer.toneMapping = toneMapping; + renderer.outputEncoding = outputEncoding; + renderer.setClearColor( clearColor, clearAlpha ); + + }, + + _textureToCubeUV: function ( texture, cubeUVRenderTarget ) { + + var renderer = this._renderer; + + if ( texture.isCubeTexture ) { + + if ( this._cubemapShader == null ) { + + this._cubemapShader = _getCubemapShader(); + + } + + } else { + + if ( this._equirectShader == null ) { + + this._equirectShader = _getEquirectShader(); + + } + + } + + var material = texture.isCubeTexture ? this._cubemapShader : this._equirectShader; + var mesh = new Mesh( _lodPlanes[ 0 ], material ); + + var 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: function ( cubeUVRenderTarget ) { + + var renderer = this._renderer; + var autoClear = renderer.autoClear; + renderer.autoClear = false; + + for ( var i = 1; i < TOTAL_LODS; i ++ ) { - console.error( 'THREE.SceneUtils has been moved to /examples/js/utils/SceneUtils.js' ); + var sigma = Math.sqrt( _sigmas[ i ] * _sigmas[ i ] - _sigmas[ i - 1 ] * _sigmas[ i - 1 ] ); + + var 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: function ( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { + + var pingPongRenderTarget = this._pingPongRenderTarget; + + this._halfBlur( + cubeUVRenderTarget, + pingPongRenderTarget, + lodIn, + lodOut, + sigma, + 'latitudinal', + poleAxis ); + + this._halfBlur( + pingPongRenderTarget, + cubeUVRenderTarget, + lodOut, + lodOut, + sigma, + 'longitudinal', + poleAxis ); + + }, + + _halfBlur: function ( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { + + var renderer = this._renderer; + var 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. + var STANDARD_DEVIATIONS = 3; + + var blurMesh = new Mesh( _lodPlanes[ lodOut ], blurMaterial ); + var blurUniforms = blurMaterial.uniforms; + + var pixels = _sizeLods[ lodIn ] - 1; + var radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); + var sigmaPixels = sigmaRadians / radiansPerPixel; + var 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) ); + + } + + var weights = []; + var sum = 0; + + for ( var i = 0; i < MAX_SAMPLES; ++ i ) { + + var x$1 = i / sigmaPixels; + var weight = Math.exp( - x$1 * x$1 / 2 ); + weights.push( weight ); + + if ( i == 0 ) { + + sum += weight; + + } else if ( i < samples ) { + + sum += 2 * weight; + + } + + } + + for ( var i$1 = 0; i$1 < weights.length; i$1 ++ ) { + + weights[ i$1 ] = weights[ i$1 ] / 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 ]; + + var outputSize = _sizeLods[ lodOut ]; + var x = 3 * Math.max( 0, SIZE_MAX - 2 * outputSize ); + var 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 ) { - function LensFlare() { + if ( texture === undefined || texture.type !== UnsignedByteType ) { return false; } - console.error( 'THREE.LensFlare has been moved to /examples/js/objects/Lensflare.js' ); + return texture.encoding === LinearEncoding || texture.encoding === sRGBEncoding || texture.encoding === GammaEncoding; } - exports.WebGLRenderTargetCube = WebGLRenderTargetCube; - exports.WebGLRenderTarget = WebGLRenderTarget; - exports.WebGLRenderer = WebGLRenderer; - exports.ShaderLib = ShaderLib; - exports.UniformsLib = UniformsLib; - exports.UniformsUtils = UniformsUtils; - exports.ShaderChunk = ShaderChunk; - exports.FogExp2 = FogExp2; - exports.Fog = Fog; - exports.Scene = Scene; - exports.Sprite = Sprite; - exports.LOD = LOD; - exports.SkinnedMesh = SkinnedMesh; - exports.Skeleton = Skeleton; - exports.Bone = Bone; - exports.Mesh = Mesh; - exports.LineSegments = LineSegments; - exports.LineLoop = LineLoop; - exports.Line = Line; - exports.Points = Points; - exports.Group = Group; - exports.VideoTexture = VideoTexture; - exports.DataTexture = DataTexture; - exports.DataTexture3D = DataTexture3D; - exports.CompressedTexture = CompressedTexture; - exports.CubeTexture = CubeTexture; - exports.CanvasTexture = CanvasTexture; - exports.DepthTexture = DepthTexture; - exports.Texture = Texture; - exports.AnimationLoader = AnimationLoader; - exports.CompressedTextureLoader = CompressedTextureLoader; - exports.DataTextureLoader = DataTextureLoader; - exports.CubeTextureLoader = CubeTextureLoader; - exports.TextureLoader = TextureLoader; - exports.ObjectLoader = ObjectLoader; - exports.MaterialLoader = MaterialLoader; - exports.BufferGeometryLoader = BufferGeometryLoader; - exports.DefaultLoadingManager = DefaultLoadingManager; - exports.LoadingManager = LoadingManager; - exports.JSONLoader = JSONLoader; - exports.ImageLoader = ImageLoader; - exports.ImageBitmapLoader = ImageBitmapLoader; - exports.FontLoader = FontLoader; - exports.FileLoader = FileLoader; - exports.Loader = Loader; - exports.LoaderUtils = LoaderUtils; - exports.Cache = Cache; - exports.AudioLoader = AudioLoader; - exports.SpotLightShadow = SpotLightShadow; - exports.SpotLight = SpotLight; - exports.PointLight = PointLight; - exports.RectAreaLight = RectAreaLight; - exports.HemisphereLight = HemisphereLight; - exports.DirectionalLightShadow = DirectionalLightShadow; - exports.DirectionalLight = DirectionalLight; - exports.AmbientLight = AmbientLight; - exports.LightShadow = LightShadow; - exports.Light = Light; - exports.StereoCamera = StereoCamera; - exports.PerspectiveCamera = PerspectiveCamera; - exports.OrthographicCamera = OrthographicCamera; - exports.CubeCamera = CubeCamera; - exports.ArrayCamera = ArrayCamera; - exports.Camera = Camera; - exports.AudioListener = AudioListener; - exports.PositionalAudio = PositionalAudio; - exports.AudioContext = AudioContext; - exports.AudioAnalyser = AudioAnalyser; - exports.Audio = Audio; - exports.VectorKeyframeTrack = VectorKeyframeTrack; - exports.StringKeyframeTrack = StringKeyframeTrack; - exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack; - exports.NumberKeyframeTrack = NumberKeyframeTrack; - exports.ColorKeyframeTrack = ColorKeyframeTrack; - exports.BooleanKeyframeTrack = BooleanKeyframeTrack; - exports.PropertyMixer = PropertyMixer; - exports.PropertyBinding = PropertyBinding; - exports.KeyframeTrack = KeyframeTrack; - exports.AnimationUtils = AnimationUtils; - exports.AnimationObjectGroup = AnimationObjectGroup; - exports.AnimationMixer = AnimationMixer; - exports.AnimationClip = AnimationClip; - exports.Uniform = Uniform; - exports.InstancedBufferGeometry = InstancedBufferGeometry; - exports.BufferGeometry = BufferGeometry; - exports.Geometry = Geometry; - exports.InterleavedBufferAttribute = InterleavedBufferAttribute; - exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer; - exports.InterleavedBuffer = InterleavedBuffer; - exports.InstancedBufferAttribute = InstancedBufferAttribute; - exports.Face3 = Face3; - exports.Object3D = Object3D; - exports.Raycaster = Raycaster; - exports.Layers = Layers; - exports.EventDispatcher = EventDispatcher; - exports.Clock = Clock; - exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant; - exports.LinearInterpolant = LinearInterpolant; - exports.DiscreteInterpolant = DiscreteInterpolant; - exports.CubicInterpolant = CubicInterpolant; - exports.Interpolant = Interpolant; - exports.Triangle = Triangle; - exports.Math = _Math; - exports.Spherical = Spherical; - exports.Cylindrical = Cylindrical; - exports.Plane = Plane; - exports.Frustum = Frustum; - exports.Sphere = Sphere; - exports.Ray = Ray; - exports.Matrix4 = Matrix4; - exports.Matrix3 = Matrix3; - exports.Box3 = Box3; - exports.Box2 = Box2; - exports.Line3 = Line3; - exports.Euler = Euler; - exports.Vector4 = Vector4; - exports.Vector3 = Vector3; - exports.Vector2 = Vector2; - exports.Quaternion = Quaternion; - exports.Color = Color; - exports.ImmediateRenderObject = ImmediateRenderObject; - exports.VertexNormalsHelper = VertexNormalsHelper; - exports.SpotLightHelper = SpotLightHelper; - exports.SkeletonHelper = SkeletonHelper; - exports.PointLightHelper = PointLightHelper; - exports.RectAreaLightHelper = RectAreaLightHelper; - exports.HemisphereLightHelper = HemisphereLightHelper; - exports.GridHelper = GridHelper; - exports.PolarGridHelper = PolarGridHelper; - exports.FaceNormalsHelper = FaceNormalsHelper; - exports.DirectionalLightHelper = DirectionalLightHelper; - exports.CameraHelper = CameraHelper; - exports.BoxHelper = BoxHelper; - exports.Box3Helper = Box3Helper; - exports.PlaneHelper = PlaneHelper; - exports.ArrowHelper = ArrowHelper; - exports.AxesHelper = AxesHelper; - exports.Shape = Shape; - exports.Path = Path; - exports.ShapePath = ShapePath; - exports.Font = Font; - exports.CurvePath = CurvePath; - exports.Curve = Curve; - exports.ImageUtils = ImageUtils; - exports.ShapeUtils = ShapeUtils; - exports.WebGLUtils = WebGLUtils; - exports.WireframeGeometry = WireframeGeometry; - exports.ParametricGeometry = ParametricGeometry; - exports.ParametricBufferGeometry = ParametricBufferGeometry; - exports.TetrahedronGeometry = TetrahedronGeometry; - exports.TetrahedronBufferGeometry = TetrahedronBufferGeometry; - exports.OctahedronGeometry = OctahedronGeometry; - exports.OctahedronBufferGeometry = OctahedronBufferGeometry; - exports.IcosahedronGeometry = IcosahedronGeometry; - exports.IcosahedronBufferGeometry = IcosahedronBufferGeometry; - exports.DodecahedronGeometry = DodecahedronGeometry; - exports.DodecahedronBufferGeometry = DodecahedronBufferGeometry; - exports.PolyhedronGeometry = PolyhedronGeometry; - exports.PolyhedronBufferGeometry = PolyhedronBufferGeometry; - exports.TubeGeometry = TubeGeometry; - exports.TubeBufferGeometry = TubeBufferGeometry; - exports.TorusKnotGeometry = TorusKnotGeometry; - exports.TorusKnotBufferGeometry = TorusKnotBufferGeometry; - exports.TorusGeometry = TorusGeometry; - exports.TorusBufferGeometry = TorusBufferGeometry; - exports.TextGeometry = TextGeometry; - exports.TextBufferGeometry = TextBufferGeometry; - exports.SphereGeometry = SphereGeometry; - exports.SphereBufferGeometry = SphereBufferGeometry; - exports.RingGeometry = RingGeometry; - exports.RingBufferGeometry = RingBufferGeometry; - exports.PlaneGeometry = PlaneGeometry; - exports.PlaneBufferGeometry = PlaneBufferGeometry; - exports.LatheGeometry = LatheGeometry; - exports.LatheBufferGeometry = LatheBufferGeometry; - exports.ShapeGeometry = ShapeGeometry; - exports.ShapeBufferGeometry = ShapeBufferGeometry; - exports.ExtrudeGeometry = ExtrudeGeometry; - exports.ExtrudeBufferGeometry = ExtrudeBufferGeometry; - exports.EdgesGeometry = EdgesGeometry; - exports.ConeGeometry = ConeGeometry; - exports.ConeBufferGeometry = ConeBufferGeometry; - exports.CylinderGeometry = CylinderGeometry; - exports.CylinderBufferGeometry = CylinderBufferGeometry; - exports.CircleGeometry = CircleGeometry; - exports.CircleBufferGeometry = CircleBufferGeometry; - exports.BoxGeometry = BoxGeometry; + function _createPlanes() { + + var _lodPlanes = []; + var _sizeLods = []; + var _sigmas = []; + + var lod = LOD_MAX; + + for ( var i = 0; i < TOTAL_LODS; i ++ ) { + + var sizeLod = Math.pow( 2, lod ); + _sizeLods.push( sizeLod ); + var 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 ); + + var texelSize = 1.0 / ( sizeLod - 1 ); + var min = - texelSize / 2; + var max = 1 + texelSize / 2; + var uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; + + var cubeFaces = 6; + var vertices = 6; + var positionSize = 3; + var uvSize = 2; + var faceIndexSize = 1; + + var position = new Float32Array( positionSize * vertices * cubeFaces ); + var uv = new Float32Array( uvSize * vertices * cubeFaces ); + var faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); + + for ( var face = 0; face < cubeFaces; face ++ ) { + + var x = ( face % 3 ) * 2 / 3 - 1; + var y = face > 2 ? 0 : - 1; + var 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 ); + var fill = [ face, face, face, face, face, face ]; + faceIndex.set( fill, faceIndexSize * vertices * face ); + + } + + var 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: _lodPlanes, _sizeLods: _sizeLods, _sigmas: _sigmas }; + + } + + function _createRenderTarget( params ) { + + var 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 ) { + + var weights = new Float32Array( maxSamples ); + var poleAxis = new Vector3( 0, 1, 0 ); + var 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 */("\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\t\t\tuniform int samples;\n\t\t\tuniform float weights[ n ];\n\t\t\tuniform bool latitudinal;\n\t\t\tuniform float dTheta;\n\t\t\tuniform float mipInt;\n\t\t\tuniform vec3 poleAxis;\n\n\t\t\t" + (_getEncodings()) + "\n\n\t\t\t#define ENVMAP_TYPE_CUBE_UV\n\t\t\t#include \n\n\t\t\tvec3 getSample( float theta, vec3 axis ) {\n\n\t\t\t\tfloat cosTheta = cos( theta );\n\t\t\t\t// Rodrigues' axis-angle rotation\n\t\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross( axis, vOutputDirection ) * sin( theta )\n\t\t\t\t\t+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );\n\n\t\t\t\treturn bilinearCubeUV( envMap, sampleDirection, mipInt );\n\n\t\t\t}\n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );\n\n\t\t\t\tif ( all( equal( axis, vec3( 0.0 ) ) ) ) {\n\n\t\t\t\t\taxis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );\n\n\t\t\t\t}\n\n\t\t\t\taxis = normalize( axis );\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );\n\n\t\t\t\tfor ( int i = 1; i < n; i++ ) {\n\n\t\t\t\t\tif ( i >= samples ) {\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfloat theta = dTheta * float( i );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( theta, axis );\n\n\t\t\t\t}\n\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t"), + + blending: NoBlending, + depthTest: false, + depthWrite: false + + } ); + + return shaderMaterial; + + } + + function _getEquirectShader() { + + var texelSize = new Vector2( 1, 1 ); + var shaderMaterial = new RawShaderMaterial( { + + name: 'EquirectangularToCubeUV', + + uniforms: { + 'envMap': { value: null }, + 'texelSize': { value: texelSize }, + 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } + }, + + vertexShader: _getCommonVertexShader(), + + fragmentShader: /* glsl */("\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\t\t\tuniform vec2 texelSize;\n\n\t\t\t" + (_getEncodings()) + "\n\n\t\t\t#include \n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\n\t\t\t\tvec3 outputDirection = normalize( vOutputDirection );\n\t\t\t\tvec2 uv = equirectUv( outputDirection );\n\n\t\t\t\tvec2 f = fract( uv / texelSize - 0.5 );\n\t\t\t\tuv -= f * texelSize;\n\t\t\t\tvec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.x += texelSize.x;\n\t\t\t\tvec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.y += texelSize.y;\n\t\t\t\tvec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.x -= texelSize.x;\n\t\t\t\tvec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\n\t\t\t\tvec3 tm = mix( tl, tr, f.x );\n\t\t\t\tvec3 bm = mix( bl, br, f.x );\n\t\t\t\tgl_FragColor.rgb = mix( tm, bm, f.y );\n\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t"), + + blending: NoBlending, + depthTest: false, + depthWrite: false + + } ); + + return shaderMaterial; + + } + + function _getCubemapShader() { + + var shaderMaterial = new RawShaderMaterial( { + + name: 'CubemapToCubeUV', + + uniforms: { + 'envMap': { value: null }, + 'inputEncoding': { value: ENCODINGS[ LinearEncoding ] }, + 'outputEncoding': { value: ENCODINGS[ LinearEncoding ] } + }, + + vertexShader: _getCommonVertexShader(), + + fragmentShader: /* glsl */("\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform samplerCube envMap;\n\n\t\t\t" + (_getEncodings()) + "\n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb;\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t"), + + blending: NoBlending, + depthTest: false, + depthWrite: false + + } ); + + return shaderMaterial; + + } + + function _getCommonVertexShader() { + + return /* glsl */"\n\n\t\tprecision mediump float;\n\t\tprecision mediump int;\n\n\t\tattribute vec3 position;\n\t\tattribute vec2 uv;\n\t\tattribute float faceIndex;\n\n\t\tvarying vec3 vOutputDirection;\n\n\t\t// RH coordinate system; PMREM face-indexing convention\n\t\tvec3 getDirection( vec2 uv, float face ) {\n\n\t\t\tuv = 2.0 * uv - 1.0;\n\n\t\t\tvec3 direction = vec3( uv, 1.0 );\n\n\t\t\tif ( face == 0.0 ) {\n\n\t\t\t\tdirection = direction.zyx; // ( 1, v, u ) pos x\n\n\t\t\t} else if ( face == 1.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xz *= -1.0; // ( -u, 1, -v ) pos y\n\n\t\t\t} else if ( face == 2.0 ) {\n\n\t\t\t\tdirection.x *= -1.0; // ( -u, v, 1 ) pos z\n\n\t\t\t} else if ( face == 3.0 ) {\n\n\t\t\t\tdirection = direction.zyx;\n\t\t\t\tdirection.xz *= -1.0; // ( -1, v, -u ) neg x\n\n\t\t\t} else if ( face == 4.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xy *= -1.0; // ( -u, -1, v ) neg y\n\n\t\t\t} else if ( face == 5.0 ) {\n\n\t\t\t\tdirection.z *= -1.0; // ( u, v, -1 ) neg z\n\n\t\t\t}\n\n\t\t\treturn direction;\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvOutputDirection = getDirection( uv, faceIndex );\n\t\t\tgl_Position = vec4( position, 1.0 );\n\n\t\t}\n\t"; + + } + + function _getEncodings() { + + return /* glsl */"\n\n\t\tuniform int inputEncoding;\n\t\tuniform int outputEncoding;\n\n\t\t#include \n\n\t\tvec4 inputTexelToLinear( vec4 value ) {\n\n\t\t\tif ( inputEncoding == 0 ) {\n\n\t\t\t\treturn value;\n\n\t\t\t} else if ( inputEncoding == 1 ) {\n\n\t\t\t\treturn sRGBToLinear( value );\n\n\t\t\t} else if ( inputEncoding == 2 ) {\n\n\t\t\t\treturn RGBEToLinear( value );\n\n\t\t\t} else if ( inputEncoding == 3 ) {\n\n\t\t\t\treturn RGBMToLinear( value, 7.0 );\n\n\t\t\t} else if ( inputEncoding == 4 ) {\n\n\t\t\t\treturn RGBMToLinear( value, 16.0 );\n\n\t\t\t} else if ( inputEncoding == 5 ) {\n\n\t\t\t\treturn RGBDToLinear( value, 256.0 );\n\n\t\t\t} else {\n\n\t\t\t\treturn GammaToLinear( value, 2.2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvec4 linearToOutputTexel( vec4 value ) {\n\n\t\t\tif ( outputEncoding == 0 ) {\n\n\t\t\t\treturn value;\n\n\t\t\t} else if ( outputEncoding == 1 ) {\n\n\t\t\t\treturn LinearTosRGB( value );\n\n\t\t\t} else if ( outputEncoding == 2 ) {\n\n\t\t\t\treturn LinearToRGBE( value );\n\n\t\t\t} else if ( outputEncoding == 3 ) {\n\n\t\t\t\treturn LinearToRGBM( value, 7.0 );\n\n\t\t\t} else if ( outputEncoding == 4 ) {\n\n\t\t\t\treturn LinearToRGBM( value, 16.0 );\n\n\t\t\t} else if ( outputEncoding == 5 ) {\n\n\t\t\t\treturn LinearToRGBD( value, 256.0 );\n\n\t\t\t} else {\n\n\t\t\t\treturn LinearToGamma( value, 2.2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvec4 envMapTexelToLinear( vec4 color ) {\n\n\t\t\treturn inputTexelToLinear( color );\n\n\t\t}\n\t"; + + } + + function Face4( a, b, c, d, normal, color, materialIndex ) { + + console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' ); + return new Face3( a, b, c, normal, color, materialIndex ); + + } + + var LineStrip = 0; + var LinePieces = 1; + var NoColors = 0; + var FaceColors = 1; + var VertexColors = 2; + + function MeshFaceMaterial( materials ) { + + console.warn( 'THREE.MeshFaceMaterial has been removed. Use an Array instead.' ); + return materials; + + } + + function MultiMaterial( materials ) { + + if ( materials === undefined ) { 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; + + }; + + // + + Object.assign( CurvePath.prototype, { + + createPointsGeometry: function ( divisions ) { + + console.warn( 'THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + + // generate geometry from path points (for Line or Points objects) + + var pts = this.getPoints( divisions ); + return this.createGeometry( pts ); + + }, + + createSpacedPointsGeometry: function ( divisions ) { + + console.warn( 'THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + + // generate geometry from equidistant sampling along the path + + var pts = this.getSpacedPoints( divisions ); + return this.createGeometry( pts ); + + }, + + createGeometry: function ( points ) { + + console.warn( 'THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.' ); + + var geometry = new Geometry(); + + for ( var i = 0, l = points.length; i < l; i ++ ) { + + var point = points[ i ]; + geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) ); + + } + + return geometry; + + } + + } ); + + // + + Object.assign( Path.prototype, { + + fromPoints: function ( points ) { + + console.warn( 'THREE.Path: .fromPoints() has been renamed to .setFromPoints().' ); + return this.setFromPoints( points ); + + } + + } ); + + // + + function ClosedSplineCurve3( points ) { + + console.warn( 'THREE.ClosedSplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); + + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; + this.closed = true; + + } + + ClosedSplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); + + // + + function SplineCurve3( points ) { + + console.warn( 'THREE.SplineCurve3 has been deprecated. Use THREE.CatmullRomCurve3 instead.' ); + + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; + + } + + SplineCurve3.prototype = Object.create( CatmullRomCurve3.prototype ); + + // + + function Spline( points ) { + + console.warn( 'THREE.Spline has been removed. Use THREE.CatmullRomCurve3 instead.' ); + + CatmullRomCurve3.call( this, points ); + this.type = 'catmullrom'; + + } + + Spline.prototype = Object.create( CatmullRomCurve3.prototype ); + + Object.assign( Spline.prototype, { + + initFromArray: function ( /* a */ ) { + + console.error( 'THREE.Spline: .initFromArray() has been removed.' ); + + }, + getControlPointsArray: function ( /* optionalTarget */ ) { + + console.error( 'THREE.Spline: .getControlPointsArray() has been removed.' ); + + }, + reparametrizeByArcLength: function ( /* samplingCoef */ ) { + + console.error( 'THREE.Spline: .reparametrizeByArcLength() has been removed.' ); + + } + + } ); + + // + + 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 } ) ); + + } + + // + + Object.assign( 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 ); + + } + + Object.assign( ObjectLoader.prototype, { + + setTexturePath: function ( value ) { + + console.warn( 'THREE.ObjectLoader: .setTexturePath() has been renamed to .setResourcePath().' ); + return this.setResourcePath( value ); + + } + + } ); + + // + + Object.assign( Box2.prototype, { + + center: function ( optionalTarget ) { + + console.warn( 'THREE.Box2: .center() has been renamed to .getCenter().' ); + return this.getCenter( optionalTarget ); + + }, + empty: function () { + + console.warn( 'THREE.Box2: .empty() has been renamed to .isEmpty().' ); + return this.isEmpty(); + + }, + isIntersectionBox: function ( box ) { + + console.warn( 'THREE.Box2: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); + + }, + size: function ( optionalTarget ) { + + console.warn( 'THREE.Box2: .size() has been renamed to .getSize().' ); + return this.getSize( optionalTarget ); + + } + } ); + + Object.assign( Box3.prototype, { + + center: function ( optionalTarget ) { + + console.warn( 'THREE.Box3: .center() has been renamed to .getCenter().' ); + return this.getCenter( optionalTarget ); + + }, + empty: function () { + + console.warn( 'THREE.Box3: .empty() has been renamed to .isEmpty().' ); + return this.isEmpty(); + + }, + isIntersectionBox: function ( box ) { + + console.warn( 'THREE.Box3: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); + + }, + isIntersectionSphere: function ( sphere ) { + + console.warn( 'THREE.Box3: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); + return this.intersectsSphere( sphere ); + + }, + size: function ( optionalTarget ) { + + console.warn( 'THREE.Box3: .size() has been renamed to .getSize().' ); + return this.getSize( optionalTarget ); + + } + } ); + + Object.assign( 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 ); + + }; + + Object.assign( MathUtils, { + + random16: function () { + + console.warn( 'THREE.Math: .random16() has been deprecated. Use Math.random() instead.' ); + return Math.random(); + + }, + + nearestPowerOfTwo: function ( value ) { + + console.warn( 'THREE.Math: .nearestPowerOfTwo() has been renamed to .floorPowerOfTwo().' ); + return MathUtils.floorPowerOfTwo( value ); + + }, + + nextPowerOfTwo: function ( value ) { + + console.warn( 'THREE.Math: .nextPowerOfTwo() has been renamed to .ceilPowerOfTwo().' ); + return MathUtils.ceilPowerOfTwo( value ); + + } + + } ); + + Object.assign( Matrix3.prototype, { + + flattenToArrayOffset: function ( array, offset ) { + + console.warn( "THREE.Matrix3: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); + return this.toArray( array, offset ); + + }, + multiplyVector3: function ( vector ) { + + console.warn( 'THREE.Matrix3: .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); + return vector.applyMatrix3( this ); + + }, + multiplyVector3Array: function ( /* a */ ) { + + console.error( 'THREE.Matrix3: .multiplyVector3Array() has been removed.' ); + + }, + applyToBufferAttribute: function ( attribute ) { + + console.warn( 'THREE.Matrix3: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix3( matrix ) instead.' ); + return attribute.applyMatrix3( this ); + + }, + applyToVector3Array: function ( /* array, offset, length */ ) { + + console.error( 'THREE.Matrix3: .applyToVector3Array() has been removed.' ); + + } + + } ); + + Object.assign( Matrix4.prototype, { + + extractPosition: function ( m ) { + + console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' ); + return this.copyPosition( m ); + + }, + flattenToArrayOffset: function ( array, offset ) { + + console.warn( "THREE.Matrix4: .flattenToArrayOffset() has been deprecated. Use .toArray() instead." ); + return this.toArray( array, offset ); + + }, + getPosition: function () { + + console.warn( 'THREE.Matrix4: .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); + return new Vector3().setFromMatrixColumn( this, 3 ); + + }, + setRotationFromQuaternion: function ( q ) { + + console.warn( 'THREE.Matrix4: .setRotationFromQuaternion() has been renamed to .makeRotationFromQuaternion().' ); + return this.makeRotationFromQuaternion( q ); + + }, + multiplyToArray: function () { + + console.warn( 'THREE.Matrix4: .multiplyToArray() has been removed.' ); + + }, + multiplyVector3: function ( vector ) { + + console.warn( 'THREE.Matrix4: .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + multiplyVector4: function ( vector ) { + + console.warn( 'THREE.Matrix4: .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + multiplyVector3Array: function ( /* a */ ) { + + console.error( 'THREE.Matrix4: .multiplyVector3Array() has been removed.' ); + + }, + rotateAxis: function ( v ) { + + console.warn( 'THREE.Matrix4: .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); + v.transformDirection( this ); + + }, + crossVector: function ( vector ) { + + console.warn( 'THREE.Matrix4: .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); + return vector.applyMatrix4( this ); + + }, + translate: function () { + + console.error( 'THREE.Matrix4: .translate() has been removed.' ); + + }, + rotateX: function () { + + console.error( 'THREE.Matrix4: .rotateX() has been removed.' ); + + }, + rotateY: function () { + + console.error( 'THREE.Matrix4: .rotateY() has been removed.' ); + + }, + rotateZ: function () { + + console.error( 'THREE.Matrix4: .rotateZ() has been removed.' ); + + }, + rotateByAxis: function () { + + console.error( 'THREE.Matrix4: .rotateByAxis() has been removed.' ); + + }, + applyToBufferAttribute: function ( attribute ) { + + console.warn( 'THREE.Matrix4: .applyToBufferAttribute() has been removed. Use attribute.applyMatrix4( matrix ) instead.' ); + return attribute.applyMatrix4( this ); + + }, + applyToVector3Array: function ( /* array, offset, length */ ) { + + console.error( 'THREE.Matrix4: .applyToVector3Array() has been removed.' ); + + }, + 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 ); + + } + + } ); + + 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 ); + + }; + + Object.assign( Ray.prototype, { + + isIntersectionBox: function ( box ) { + + console.warn( 'THREE.Ray: .isIntersectionBox() has been renamed to .intersectsBox().' ); + return this.intersectsBox( box ); + + }, + isIntersectionPlane: function ( plane ) { + + console.warn( 'THREE.Ray: .isIntersectionPlane() has been renamed to .intersectsPlane().' ); + return this.intersectsPlane( plane ); + + }, + isIntersectionSphere: function ( sphere ) { + + console.warn( 'THREE.Ray: .isIntersectionSphere() has been renamed to .intersectsSphere().' ); + return this.intersectsSphere( sphere ); + + } + + } ); + + Object.assign( Triangle.prototype, { + + area: function () { + + console.warn( 'THREE.Triangle: .area() has been renamed to .getArea().' ); + return this.getArea(); + + }, + barycoordFromPoint: function ( point, target ) { + + console.warn( 'THREE.Triangle: .barycoordFromPoint() has been renamed to .getBarycoord().' ); + return this.getBarycoord( point, target ); + + }, + midpoint: function ( target ) { + + console.warn( 'THREE.Triangle: .midpoint() has been renamed to .getMidpoint().' ); + return this.getMidpoint( target ); + + }, + normal: function ( target ) { + + console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' ); + return this.getNormal( target ); + + }, + plane: function ( target ) { + + console.warn( 'THREE.Triangle: .plane() has been renamed to .getPlane().' ); + return this.getPlane( target ); + + } + + } ); + + Object.assign( 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 ); + + }, + normal: function ( a, b, c, target ) { + + console.warn( 'THREE.Triangle: .normal() has been renamed to .getNormal().' ); + return Triangle.getNormal( a, b, c, target ); + + } + + } ); + + Object.assign( Shape.prototype, { + + extractAllPoints: function ( divisions ) { + + console.warn( 'THREE.Shape: .extractAllPoints() has been removed. Use .extractPoints() instead.' ); + return this.extractPoints( divisions ); + + }, + extrude: function ( options ) { + + console.warn( 'THREE.Shape: .extrude() has been removed. Use ExtrudeGeometry() instead.' ); + return new ExtrudeGeometry( this, options ); + + }, + makeGeometry: function ( options ) { + + console.warn( 'THREE.Shape: .makeGeometry() has been removed. Use ShapeGeometry() instead.' ); + return new ShapeGeometry( this, options ); + + } + + } ); + + Object.assign( Vector2.prototype, { + + fromAttribute: function ( attribute, index, offset ) { + + console.warn( 'THREE.Vector2: .fromAttribute() has been renamed to .fromBufferAttribute().' ); + return this.fromBufferAttribute( attribute, index, offset ); + + }, + distanceToManhattan: function ( v ) { + + console.warn( 'THREE.Vector2: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); + return this.manhattanDistanceTo( v ); + + }, + lengthManhattan: function () { + + console.warn( 'THREE.Vector2: .lengthManhattan() has been renamed to .manhattanLength().' ); + return this.manhattanLength(); + + } + + } ); + + Object.assign( Vector3.prototype, { + + setEulerFromRotationMatrix: function () { + + console.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' ); + + }, + setEulerFromQuaternion: function () { + + console.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' ); + + }, + getPositionFromMatrix: function ( m ) { + + console.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' ); + return this.setFromMatrixPosition( m ); + + }, + getScaleFromMatrix: function ( m ) { + + console.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' ); + return this.setFromMatrixScale( m ); + + }, + getColumnFromMatrix: function ( index, matrix ) { + + console.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' ); + return this.setFromMatrixColumn( matrix, index ); + + }, + applyProjection: function ( m ) { + + console.warn( 'THREE.Vector3: .applyProjection() has been removed. Use .applyMatrix4( m ) instead.' ); + return this.applyMatrix4( m ); + + }, + fromAttribute: function ( attribute, index, offset ) { + + console.warn( 'THREE.Vector3: .fromAttribute() has been renamed to .fromBufferAttribute().' ); + return this.fromBufferAttribute( attribute, index, offset ); + + }, + distanceToManhattan: function ( v ) { + + console.warn( 'THREE.Vector3: .distanceToManhattan() has been renamed to .manhattanDistanceTo().' ); + return this.manhattanDistanceTo( v ); + + }, + lengthManhattan: function () { + + console.warn( 'THREE.Vector3: .lengthManhattan() has been renamed to .manhattanLength().' ); + return this.manhattanLength(); + + } + + } ); + + Object.assign( Vector4.prototype, { + + fromAttribute: function ( attribute, index, offset ) { + + console.warn( 'THREE.Vector4: .fromAttribute() has been renamed to .fromBufferAttribute().' ); + return this.fromBufferAttribute( attribute, index, offset ); + + }, + lengthManhattan: function () { + + console.warn( 'THREE.Vector4: .lengthManhattan() has been renamed to .manhattanLength().' ); + return this.manhattanLength(); + + } + + } ); + + // + + Object.assign( Geometry.prototype, { + + computeTangents: function () { + + console.error( 'THREE.Geometry: .computeTangents() has been removed.' ); + + }, + computeLineDistances: function () { + + console.error( 'THREE.Geometry: .computeLineDistances() has been removed. Use THREE.Line.computeLineDistances() instead.' ); + + }, + applyMatrix: function ( matrix ) { + + console.warn( 'THREE.Geometry: .applyMatrix() has been renamed to .applyMatrix4().' ); + return this.applyMatrix4( matrix ); + + } + + } ); + + Object.assign( Object3D.prototype, { + + getChildByName: function ( name ) { + + console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' ); + return this.getObjectByName( name ); + + }, + renderDepth: function () { + + console.warn( 'THREE.Object3D: .renderDepth has been removed. Use .renderOrder, instead.' ); + + }, + translate: function ( distance, axis ) { + + console.warn( 'THREE.Object3D: .translate() has been removed. Use .translateOnAxis( axis, distance ) instead.' ); + return this.translateOnAxis( axis, distance ); + + }, + getWorldRotation: function () { + + console.error( 'THREE.Object3D: .getWorldRotation() has been removed. Use THREE.Object3D.getWorldQuaternion( target ) instead.' ); + + }, + 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.' ); + + } + } + + } ); + + Object.assign( 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.' ); + + } + } + + } ); + + Object.defineProperties( LOD.prototype, { + + objects: { + get: function () { + + console.warn( 'THREE.LOD: .objects has been renamed to .levels.' ); + return this.levels; + + } + } + + } ); + + Object.defineProperty( Skeleton.prototype, 'useVertexTexture', { + + get: function () { + + console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); + + }, + set: function () { + + console.warn( 'THREE.Skeleton: useVertexTexture has been removed.' ); + + } + + } ); + + SkinnedMesh.prototype.initBones = function () { + + console.error( 'THREE.SkinnedMesh: initBones() has been removed.' ); + + }; + + Object.defineProperty( Curve.prototype, '__arcLengthDivisions', { + + get: function () { + + console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); + return this.arcLengthDivisions; + + }, + set: function ( value ) { + + console.warn( 'THREE.Curve: .__arcLengthDivisions is now .arcLengthDivisions.' ); + this.arcLengthDivisions = value; + + } + + } ); + + // + + 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 ); + + } + } + + } ); + + Object.assign( BufferAttribute.prototype, { + setDynamic: function ( value ) { + + console.warn( 'THREE.BufferAttribute: .setDynamic() has been deprecated. Use .setUsage() instead.' ); + this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage ); + return this; + + }, + copyIndicesArray: function ( /* indices */ ) { + + console.error( 'THREE.BufferAttribute: .copyIndicesArray() has been removed.' ); + + }, + setArray: function ( /* array */ ) { + + console.error( 'THREE.BufferAttribute: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' ); + + } + } ); + + Object.assign( BufferGeometry.prototype, { + + addIndex: function ( index ) { + + console.warn( 'THREE.BufferGeometry: .addIndex() has been renamed to .setIndex().' ); + this.setIndex( index ); + + }, + 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 ); + + }, + 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 ); + + }, + clearDrawCalls: function () { + + console.warn( 'THREE.BufferGeometry: .clearDrawCalls() is now .clearGroups().' ); + this.clearGroups(); + + }, + computeTangents: function () { + + console.warn( 'THREE.BufferGeometry: .computeTangents() has been removed.' ); + + }, + computeOffsets: function () { + + console.warn( 'THREE.BufferGeometry: .computeOffsets() has been removed.' ); + + }, + removeAttribute: function ( name ) { + + console.warn( 'THREE.BufferGeometry: .removeAttribute() has been renamed to .deleteAttribute().' ); + + return this.deleteAttribute( name ); + + }, + 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; + + } + } + + } ); + + Object.defineProperties( InstancedBufferGeometry.prototype, { + + maxInstancedCount: { + get: function () { + + console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' ); + return this.instanceCount; + + }, + set: function ( value ) { + + console.warn( 'THREE.InstancedBufferGeometry: .maxInstancedCount has been renamed to .instanceCount.' ); + this.instanceCount = value; + + } + } + + } ); + + Object.defineProperties( Raycaster.prototype, { + + linePrecision: { + get: function () { + + console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' ); + return this.params.Line.threshold; + + }, + set: function ( value ) { + + console.warn( 'THREE.Raycaster: .linePrecision has been deprecated. Use .params.Line.threshold instead.' ); + this.params.Line.threshold = value; + + } + } + + } ); + + Object.defineProperties( InterleavedBuffer.prototype, { + + dynamic: { + get: function () { + + console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' ); + return this.usage === DynamicDrawUsage; + + }, + set: function ( value ) { + + console.warn( 'THREE.InterleavedBuffer: .length has been deprecated. Use .usage instead.' ); + this.setUsage( value ); + + } + } + + } ); + + Object.assign( InterleavedBuffer.prototype, { + setDynamic: function ( value ) { + + console.warn( 'THREE.InterleavedBuffer: .setDynamic() has been deprecated. Use .setUsage() instead.' ); + this.setUsage( value === true ? DynamicDrawUsage : StaticDrawUsage ); + return this; + + }, + setArray: function ( /* array */ ) { + + console.error( 'THREE.InterleavedBuffer: .setArray has been removed. Use BufferGeometry .setAttribute to replace/resize attribute buffers' ); + + } + } ); + + // + + Object.assign( ExtrudeBufferGeometry.prototype, { + + getArrays: function () { + + console.error( 'THREE.ExtrudeBufferGeometry: .getArrays() has been removed.' ); + + }, + + addShapeList: function () { + + console.error( 'THREE.ExtrudeBufferGeometry: .addShapeList() has been removed.' ); + + }, + + addShape: function () { + + console.error( 'THREE.ExtrudeBufferGeometry: .addShape() has been removed.' ); + + } + + } ); + + // + + Object.defineProperties( Uniform.prototype, { + + dynamic: { + set: function () { + + console.warn( 'THREE.Uniform: .dynamic has been removed. Use object.onBeforeRender() instead.' ); + + } + }, + onUpdate: { + value: 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; + + } + } + + } ); + + Object.defineProperties( MeshPhongMaterial.prototype, { + + metal: { + get: function () { + + console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead.' ); + return false; + + }, + set: function () { + + console.warn( 'THREE.MeshPhongMaterial: .metal has been removed. Use THREE.MeshStandardMaterial instead' ); + + } + } + + } ); + + Object.defineProperties( MeshPhysicalMaterial.prototype, { + + transparency: { + get: function () { + + console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' ); + return this.transmission; + + }, + set: function ( value ) { + + console.warn( 'THREE.MeshPhysicalMaterial: .transparency has been renamed to .transmission.' ); + this.transmission = value; + + } + } + + } ); + + 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; + + } + } + + } ); + + // + + Object.assign( 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 ); + + }, + animate: function ( callback ) { + + console.warn( 'THREE.WebGLRenderer: .animate() is now .setAnimationLoop().' ); + this.setAnimationLoop( callback ); + + }, + getCurrentRenderTarget: function () { + + console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' ); + return this.getRenderTarget(); + + }, + getMaxAnisotropy: function () { + + console.warn( 'THREE.WebGLRenderer: .getMaxAnisotropy() is now .capabilities.getMaxAnisotropy().' ); + return this.capabilities.getMaxAnisotropy(); + + }, + getPrecision: function () { + + console.warn( 'THREE.WebGLRenderer: .getPrecision() is now .capabilities.precision.' ); + return this.capabilities.precision; + + }, + resetGLState: function () { + + console.warn( 'THREE.WebGLRenderer: .resetGLState() is now .state.reset().' ); + return this.state.reset(); + + }, + supportsFloatTextures: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' ); + return this.extensions.get( 'OES_texture_float' ); + + }, + supportsHalfFloatTextures: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsHalfFloatTextures() is now .extensions.get( \'OES_texture_half_float\' ).' ); + return this.extensions.get( 'OES_texture_half_float' ); + + }, + supportsStandardDerivatives: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsStandardDerivatives() is now .extensions.get( \'OES_standard_derivatives\' ).' ); + return this.extensions.get( 'OES_standard_derivatives' ); + + }, + supportsCompressedTextureS3TC: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsCompressedTextureS3TC() is now .extensions.get( \'WEBGL_compressed_texture_s3tc\' ).' ); + return this.extensions.get( 'WEBGL_compressed_texture_s3tc' ); + + }, + supportsCompressedTexturePVRTC: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsCompressedTexturePVRTC() is now .extensions.get( \'WEBGL_compressed_texture_pvrtc\' ).' ); + return this.extensions.get( 'WEBGL_compressed_texture_pvrtc' ); + + }, + supportsBlendMinMax: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsBlendMinMax() is now .extensions.get( \'EXT_blend_minmax\' ).' ); + return this.extensions.get( 'EXT_blend_minmax' ); + + }, + supportsVertexTextures: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsVertexTextures() is now .capabilities.vertexTextures.' ); + return this.capabilities.vertexTextures; + + }, + supportsInstancedArrays: function () { + + console.warn( 'THREE.WebGLRenderer: .supportsInstancedArrays() is now .extensions.get( \'ANGLE_instanced_arrays\' ).' ); + return this.extensions.get( 'ANGLE_instanced_arrays' ); + + }, + enableScissorTest: function ( boolean ) { + + console.warn( 'THREE.WebGLRenderer: .enableScissorTest() is now .setScissorTest().' ); + this.setScissorTest( boolean ); + + }, + initMaterial: function () { + + console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' ); + + }, + addPrePlugin: function () { + + console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' ); + + }, + addPostPlugin: function () { + + console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' ); + + }, + updateShadowMap: function () { + + console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' ); + + }, + setFaceCulling: function () { + + console.warn( 'THREE.WebGLRenderer: .setFaceCulling() has been removed.' ); + + }, + allocTextureUnit: function () { + + console.warn( 'THREE.WebGLRenderer: .allocTextureUnit() has been removed.' ); + + }, + setTexture: function () { + + console.warn( 'THREE.WebGLRenderer: .setTexture() has been removed.' ); + + }, + setTexture2D: function () { + + console.warn( 'THREE.WebGLRenderer: .setTexture2D() has been removed.' ); + + }, + setTextureCube: function () { + + console.warn( 'THREE.WebGLRenderer: .setTextureCube() has been removed.' ); + + }, + 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; + + } + } + + } ); + + // + + Object.defineProperties( Audio.prototype, { + + load: { + value: function ( file ) { + + console.warn( 'THREE.Audio: .load has been deprecated. Use THREE.AudioLoader instead.' ); + var scope = this; + var audioLoader = new AudioLoader(); + audioLoader.load( file, function ( buffer ) { + + scope.setBuffer( buffer ); + + } ); + return this; + + } + }, + startTime: { + set: function () { + + console.warn( 'THREE.Audio: .startTime is now .play( delay ).' ); + + } + } + + } ); + + 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 ); + + }; + + // + + var GeometryUtils = { + + merge: function ( geometry1, geometry2, materialIndexOffset ) { + + console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' ); + var matrix; + + if ( geometry2.isMesh ) { + + geometry2.matrixAutoUpdate && geometry2.updateMatrix(); + + matrix = geometry2.matrix; + geometry2 = geometry2.geometry; + + } + + geometry1.merge( geometry2, matrix, materialIndexOffset ); + + }, + + center: function ( geometry ) { + + console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' ); + return geometry.center(); + + } + + }; + + ImageUtils.crossOrigin = undefined; + + ImageUtils.loadTexture = function ( url, mapping, onLoad, onError ) { + + console.warn( 'THREE.ImageUtils.loadTexture has been deprecated. Use THREE.TextureLoader() instead.' ); + + var loader = new TextureLoader(); + loader.setCrossOrigin( this.crossOrigin ); + + var 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.' ); + + var loader = new CubeTextureLoader(); + loader.setCrossOrigin( this.crossOrigin ); + + var 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.' ); + + } + + // + + var 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 */ + + } + + exports.ACESFilmicToneMapping = ACESFilmicToneMapping; + exports.AddEquation = AddEquation; + exports.AddOperation = AddOperation; + exports.AdditiveAnimationBlendMode = AdditiveAnimationBlendMode; + exports.AdditiveBlending = AdditiveBlending; + exports.AlphaFormat = AlphaFormat; + exports.AlwaysDepth = AlwaysDepth; + exports.AlwaysStencilFunc = AlwaysStencilFunc; + exports.AmbientLight = AmbientLight; + exports.AmbientLightProbe = AmbientLightProbe; + exports.AnimationClip = AnimationClip; + exports.AnimationLoader = AnimationLoader; + exports.AnimationMixer = AnimationMixer; + exports.AnimationObjectGroup = AnimationObjectGroup; + exports.AnimationUtils = AnimationUtils; + exports.ArcCurve = ArcCurve; + exports.ArrayCamera = ArrayCamera; + exports.ArrowHelper = ArrowHelper; + exports.Audio = Audio; + exports.AudioAnalyser = AudioAnalyser; + exports.AudioContext = AudioContext; + exports.AudioListener = AudioListener; + exports.AudioLoader = AudioLoader; + exports.AxesHelper = AxesHelper; + exports.AxisHelper = AxisHelper; + exports.BackSide = BackSide; + exports.BasicDepthPacking = BasicDepthPacking; + exports.BasicShadowMap = BasicShadowMap; + exports.BinaryTextureLoader = BinaryTextureLoader; + exports.Bone = Bone; + exports.BooleanKeyframeTrack = BooleanKeyframeTrack; + exports.BoundingBoxHelper = BoundingBoxHelper; + exports.Box2 = Box2; + exports.Box3 = Box3; + exports.Box3Helper = Box3Helper; exports.BoxBufferGeometry = BoxBufferGeometry; - exports.ShadowMaterial = ShadowMaterial; - exports.SpriteMaterial = SpriteMaterial; - exports.RawShaderMaterial = RawShaderMaterial; - exports.ShaderMaterial = ShaderMaterial; - exports.PointsMaterial = PointsMaterial; - exports.MeshPhysicalMaterial = MeshPhysicalMaterial; - exports.MeshStandardMaterial = MeshStandardMaterial; - exports.MeshPhongMaterial = MeshPhongMaterial; - exports.MeshToonMaterial = MeshToonMaterial; - exports.MeshNormalMaterial = MeshNormalMaterial; - exports.MeshLambertMaterial = MeshLambertMaterial; - exports.MeshDepthMaterial = MeshDepthMaterial; - exports.MeshDistanceMaterial = MeshDistanceMaterial; - exports.MeshBasicMaterial = MeshBasicMaterial; - exports.MeshMatcapMaterial = MeshMatcapMaterial; - exports.LineDashedMaterial = LineDashedMaterial; - exports.LineBasicMaterial = LineBasicMaterial; - exports.Material = Material; - exports.Float64BufferAttribute = Float64BufferAttribute; - exports.Float32BufferAttribute = Float32BufferAttribute; - exports.Uint32BufferAttribute = Uint32BufferAttribute; - exports.Int32BufferAttribute = Int32BufferAttribute; - exports.Uint16BufferAttribute = Uint16BufferAttribute; - exports.Int16BufferAttribute = Int16BufferAttribute; - exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute; - exports.Uint8BufferAttribute = Uint8BufferAttribute; - exports.Int8BufferAttribute = Int8BufferAttribute; + exports.BoxGeometry = BoxGeometry; + exports.BoxHelper = BoxHelper; exports.BufferAttribute = BufferAttribute; - exports.ArcCurve = ArcCurve; + exports.BufferGeometry = BufferGeometry; + exports.BufferGeometryLoader = BufferGeometryLoader; + exports.ByteType = ByteType; + exports.Cache = Cache; + exports.Camera = Camera; + exports.CameraHelper = CameraHelper; + exports.CanvasRenderer = CanvasRenderer; + exports.CanvasTexture = CanvasTexture; exports.CatmullRomCurve3 = CatmullRomCurve3; + exports.CineonToneMapping = CineonToneMapping; + exports.CircleBufferGeometry = CircleBufferGeometry; + exports.CircleGeometry = CircleGeometry; + exports.ClampToEdgeWrapping = ClampToEdgeWrapping; + exports.Clock = Clock; + exports.ClosedSplineCurve3 = ClosedSplineCurve3; + exports.Color = Color; + exports.ColorKeyframeTrack = ColorKeyframeTrack; + exports.CompressedTexture = CompressedTexture; + exports.CompressedTextureLoader = CompressedTextureLoader; + exports.ConeBufferGeometry = ConeBufferGeometry; + exports.ConeGeometry = ConeGeometry; + exports.CubeCamera = CubeCamera; + exports.CubeGeometry = BoxGeometry; + exports.CubeReflectionMapping = CubeReflectionMapping; + exports.CubeRefractionMapping = CubeRefractionMapping; + exports.CubeTexture = CubeTexture; + exports.CubeTextureLoader = CubeTextureLoader; + exports.CubeUVReflectionMapping = CubeUVReflectionMapping; + exports.CubeUVRefractionMapping = CubeUVRefractionMapping; exports.CubicBezierCurve = CubicBezierCurve; exports.CubicBezierCurve3 = CubicBezierCurve3; - exports.EllipseCurve = EllipseCurve; - exports.LineCurve = LineCurve; - exports.LineCurve3 = LineCurve3; - exports.QuadraticBezierCurve = QuadraticBezierCurve; - exports.QuadraticBezierCurve3 = QuadraticBezierCurve3; - exports.SplineCurve = SplineCurve; - exports.REVISION = REVISION; - exports.MOUSE = MOUSE; - exports.CullFaceNone = CullFaceNone; + exports.CubicInterpolant = CubicInterpolant; exports.CullFaceBack = CullFaceBack; exports.CullFaceFront = CullFaceFront; exports.CullFaceFrontBack = CullFaceFrontBack; - exports.FrontFaceDirectionCW = FrontFaceDirectionCW; - exports.FrontFaceDirectionCCW = FrontFaceDirectionCCW; - exports.BasicShadowMap = BasicShadowMap; - exports.PCFShadowMap = PCFShadowMap; - exports.PCFSoftShadowMap = PCFSoftShadowMap; - exports.FrontSide = FrontSide; - exports.BackSide = BackSide; - exports.DoubleSide = DoubleSide; - exports.FlatShading = FlatShading; - exports.SmoothShading = SmoothShading; - exports.NoColors = NoColors; - exports.FaceColors = FaceColors; - exports.VertexColors = VertexColors; - exports.NoBlending = NoBlending; - exports.NormalBlending = NormalBlending; - exports.AdditiveBlending = AdditiveBlending; - exports.SubtractiveBlending = SubtractiveBlending; - exports.MultiplyBlending = MultiplyBlending; + exports.CullFaceNone = CullFaceNone; + exports.Curve = Curve; + exports.CurvePath = CurvePath; exports.CustomBlending = CustomBlending; - exports.AddEquation = AddEquation; - exports.SubtractEquation = SubtractEquation; - exports.ReverseSubtractEquation = ReverseSubtractEquation; - exports.MinEquation = MinEquation; - exports.MaxEquation = MaxEquation; - exports.ZeroFactor = ZeroFactor; - exports.OneFactor = OneFactor; - exports.SrcColorFactor = SrcColorFactor; - exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor; - exports.SrcAlphaFactor = SrcAlphaFactor; - exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor; + exports.CustomToneMapping = CustomToneMapping; + exports.CylinderBufferGeometry = CylinderBufferGeometry; + exports.CylinderGeometry = CylinderGeometry; + exports.Cylindrical = Cylindrical; + exports.DataTexture = DataTexture; + exports.DataTexture2DArray = DataTexture2DArray; + exports.DataTexture3D = DataTexture3D; + exports.DataTextureLoader = DataTextureLoader; + exports.DecrementStencilOp = DecrementStencilOp; + exports.DecrementWrapStencilOp = DecrementWrapStencilOp; + exports.DefaultLoadingManager = DefaultLoadingManager; + exports.DepthFormat = DepthFormat; + exports.DepthStencilFormat = DepthStencilFormat; + exports.DepthTexture = DepthTexture; + exports.DirectionalLight = DirectionalLight; + exports.DirectionalLightHelper = DirectionalLightHelper; + exports.DirectionalLightShadow = DirectionalLightShadow; + exports.DiscreteInterpolant = DiscreteInterpolant; + exports.DodecahedronBufferGeometry = DodecahedronBufferGeometry; + exports.DodecahedronGeometry = DodecahedronGeometry; + exports.DoubleSide = DoubleSide; exports.DstAlphaFactor = DstAlphaFactor; - exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor; exports.DstColorFactor = DstColorFactor; - exports.OneMinusDstColorFactor = OneMinusDstColorFactor; - exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor; - exports.NeverDepth = NeverDepth; - exports.AlwaysDepth = AlwaysDepth; - exports.LessDepth = LessDepth; - exports.LessEqualDepth = LessEqualDepth; + exports.DynamicBufferAttribute = DynamicBufferAttribute; + exports.DynamicCopyUsage = DynamicCopyUsage; + exports.DynamicDrawUsage = DynamicDrawUsage; + exports.DynamicReadUsage = DynamicReadUsage; + exports.EdgesGeometry = EdgesGeometry; + exports.EdgesHelper = EdgesHelper; + exports.EllipseCurve = EllipseCurve; exports.EqualDepth = EqualDepth; - exports.GreaterEqualDepth = GreaterEqualDepth; - exports.GreaterDepth = GreaterDepth; - exports.NotEqualDepth = NotEqualDepth; - exports.MultiplyOperation = MultiplyOperation; - exports.MixOperation = MixOperation; - exports.AddOperation = AddOperation; - exports.NoToneMapping = NoToneMapping; - exports.LinearToneMapping = LinearToneMapping; - exports.ReinhardToneMapping = ReinhardToneMapping; - exports.Uncharted2ToneMapping = Uncharted2ToneMapping; - exports.CineonToneMapping = CineonToneMapping; - exports.UVMapping = UVMapping; - exports.CubeReflectionMapping = CubeReflectionMapping; - exports.CubeRefractionMapping = CubeRefractionMapping; + exports.EqualStencilFunc = EqualStencilFunc; exports.EquirectangularReflectionMapping = EquirectangularReflectionMapping; exports.EquirectangularRefractionMapping = EquirectangularRefractionMapping; - exports.SphericalReflectionMapping = SphericalReflectionMapping; - exports.CubeUVReflectionMapping = CubeUVReflectionMapping; - exports.CubeUVRefractionMapping = CubeUVRefractionMapping; - exports.RepeatWrapping = RepeatWrapping; - exports.ClampToEdgeWrapping = ClampToEdgeWrapping; + exports.Euler = Euler; + exports.EventDispatcher = EventDispatcher; + exports.ExtrudeBufferGeometry = ExtrudeBufferGeometry; + exports.ExtrudeGeometry = ExtrudeGeometry; + exports.Face3 = Face3; + exports.Face4 = Face4; + exports.FaceColors = FaceColors; + exports.FileLoader = FileLoader; + exports.FlatShading = FlatShading; + exports.Float32Attribute = Float32Attribute; + exports.Float32BufferAttribute = Float32BufferAttribute; + exports.Float64Attribute = Float64Attribute; + exports.Float64BufferAttribute = Float64BufferAttribute; + exports.FloatType = FloatType; + exports.Fog = Fog; + exports.FogExp2 = FogExp2; + exports.Font = Font; + exports.FontLoader = FontLoader; + exports.FrontSide = FrontSide; + exports.Frustum = Frustum; + exports.GammaEncoding = GammaEncoding; + exports.Geometry = Geometry; + exports.GeometryUtils = GeometryUtils; + exports.GreaterDepth = GreaterDepth; + exports.GreaterEqualDepth = GreaterEqualDepth; + exports.GreaterEqualStencilFunc = GreaterEqualStencilFunc; + exports.GreaterStencilFunc = GreaterStencilFunc; + exports.GridHelper = GridHelper; + exports.Group = Group; + exports.HalfFloatType = HalfFloatType; + exports.HemisphereLight = HemisphereLight; + exports.HemisphereLightHelper = HemisphereLightHelper; + exports.HemisphereLightProbe = HemisphereLightProbe; + exports.IcosahedronBufferGeometry = IcosahedronBufferGeometry; + exports.IcosahedronGeometry = IcosahedronGeometry; + exports.ImageBitmapLoader = ImageBitmapLoader; + exports.ImageLoader = ImageLoader; + exports.ImageUtils = ImageUtils; + exports.ImmediateRenderObject = ImmediateRenderObject; + exports.IncrementStencilOp = IncrementStencilOp; + exports.IncrementWrapStencilOp = IncrementWrapStencilOp; + exports.InstancedBufferAttribute = InstancedBufferAttribute; + exports.InstancedBufferGeometry = InstancedBufferGeometry; + exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer; + exports.InstancedMesh = InstancedMesh; + exports.Int16Attribute = Int16Attribute; + exports.Int16BufferAttribute = Int16BufferAttribute; + exports.Int32Attribute = Int32Attribute; + exports.Int32BufferAttribute = Int32BufferAttribute; + exports.Int8Attribute = Int8Attribute; + exports.Int8BufferAttribute = Int8BufferAttribute; + exports.IntType = IntType; + exports.InterleavedBuffer = InterleavedBuffer; + exports.InterleavedBufferAttribute = InterleavedBufferAttribute; + exports.Interpolant = Interpolant; + exports.InterpolateDiscrete = InterpolateDiscrete; + exports.InterpolateLinear = InterpolateLinear; + exports.InterpolateSmooth = InterpolateSmooth; + exports.InvertStencilOp = InvertStencilOp; + exports.JSONLoader = JSONLoader; + exports.KeepStencilOp = KeepStencilOp; + exports.KeyframeTrack = KeyframeTrack; + exports.LOD = LOD; + exports.LatheBufferGeometry = LatheBufferGeometry; + exports.LatheGeometry = LatheGeometry; + exports.Layers = Layers; + exports.LensFlare = LensFlare; + exports.LessDepth = LessDepth; + exports.LessEqualDepth = LessEqualDepth; + exports.LessEqualStencilFunc = LessEqualStencilFunc; + exports.LessStencilFunc = LessStencilFunc; + exports.Light = Light; + exports.LightProbe = LightProbe; + exports.LightShadow = LightShadow; + exports.Line = Line; + exports.Line3 = Line3; + exports.LineBasicMaterial = LineBasicMaterial; + exports.LineCurve = LineCurve; + exports.LineCurve3 = LineCurve3; + exports.LineDashedMaterial = LineDashedMaterial; + exports.LineLoop = LineLoop; + exports.LinePieces = LinePieces; + exports.LineSegments = LineSegments; + exports.LineStrip = LineStrip; + exports.LinearEncoding = LinearEncoding; + exports.LinearFilter = LinearFilter; + exports.LinearInterpolant = LinearInterpolant; + exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter; + exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter; + exports.LinearMipmapLinearFilter = LinearMipmapLinearFilter; + exports.LinearMipmapNearestFilter = LinearMipmapNearestFilter; + exports.LinearToneMapping = LinearToneMapping; + exports.Loader = Loader; + exports.LoaderUtils = LoaderUtils; + exports.LoadingManager = LoadingManager; + exports.LogLuvEncoding = LogLuvEncoding; + exports.LoopOnce = LoopOnce; + exports.LoopPingPong = LoopPingPong; + exports.LoopRepeat = LoopRepeat; + exports.LuminanceAlphaFormat = LuminanceAlphaFormat; + exports.LuminanceFormat = LuminanceFormat; + exports.MOUSE = MOUSE; + exports.Material = Material; + exports.MaterialLoader = MaterialLoader; + exports.Math = MathUtils; + exports.MathUtils = MathUtils; + exports.Matrix3 = Matrix3; + exports.Matrix4 = Matrix4; + exports.MaxEquation = MaxEquation; + exports.Mesh = Mesh; + exports.MeshBasicMaterial = MeshBasicMaterial; + exports.MeshDepthMaterial = MeshDepthMaterial; + exports.MeshDistanceMaterial = MeshDistanceMaterial; + exports.MeshFaceMaterial = MeshFaceMaterial; + exports.MeshLambertMaterial = MeshLambertMaterial; + exports.MeshMatcapMaterial = MeshMatcapMaterial; + exports.MeshNormalMaterial = MeshNormalMaterial; + exports.MeshPhongMaterial = MeshPhongMaterial; + exports.MeshPhysicalMaterial = MeshPhysicalMaterial; + exports.MeshStandardMaterial = MeshStandardMaterial; + exports.MeshToonMaterial = MeshToonMaterial; + exports.MinEquation = MinEquation; exports.MirroredRepeatWrapping = MirroredRepeatWrapping; + exports.MixOperation = MixOperation; + exports.MultiMaterial = MultiMaterial; + exports.MultiplyBlending = MultiplyBlending; + exports.MultiplyOperation = MultiplyOperation; exports.NearestFilter = NearestFilter; - exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter; exports.NearestMipMapLinearFilter = NearestMipMapLinearFilter; - exports.LinearFilter = LinearFilter; - exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter; - exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter; - exports.UnsignedByteType = UnsignedByteType; - exports.ByteType = ByteType; - exports.ShortType = ShortType; - exports.UnsignedShortType = UnsignedShortType; - exports.IntType = IntType; - exports.UnsignedIntType = UnsignedIntType; - exports.FloatType = FloatType; - exports.HalfFloatType = HalfFloatType; - exports.UnsignedShort4444Type = UnsignedShort4444Type; - exports.UnsignedShort5551Type = UnsignedShort5551Type; - exports.UnsignedShort565Type = UnsignedShort565Type; - exports.UnsignedInt248Type = UnsignedInt248Type; - exports.AlphaFormat = AlphaFormat; - exports.RGBFormat = RGBFormat; + exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter; + exports.NearestMipmapLinearFilter = NearestMipmapLinearFilter; + exports.NearestMipmapNearestFilter = NearestMipmapNearestFilter; + exports.NeverDepth = NeverDepth; + exports.NeverStencilFunc = NeverStencilFunc; + exports.NoBlending = NoBlending; + exports.NoColors = NoColors; + exports.NoToneMapping = NoToneMapping; + exports.NormalAnimationBlendMode = NormalAnimationBlendMode; + exports.NormalBlending = NormalBlending; + exports.NotEqualDepth = NotEqualDepth; + exports.NotEqualStencilFunc = NotEqualStencilFunc; + exports.NumberKeyframeTrack = NumberKeyframeTrack; + exports.Object3D = Object3D; + exports.ObjectLoader = ObjectLoader; + exports.ObjectSpaceNormalMap = ObjectSpaceNormalMap; + exports.OctahedronBufferGeometry = OctahedronBufferGeometry; + exports.OctahedronGeometry = OctahedronGeometry; + exports.OneFactor = OneFactor; + exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor; + exports.OneMinusDstColorFactor = OneMinusDstColorFactor; + exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor; + exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor; + exports.OrthographicCamera = OrthographicCamera; + exports.PCFShadowMap = PCFShadowMap; + exports.PCFSoftShadowMap = PCFSoftShadowMap; + exports.PMREMGenerator = PMREMGenerator; + exports.ParametricBufferGeometry = ParametricBufferGeometry; + exports.ParametricGeometry = ParametricGeometry; + exports.Particle = Particle; + exports.ParticleBasicMaterial = ParticleBasicMaterial; + exports.ParticleSystem = ParticleSystem; + exports.ParticleSystemMaterial = ParticleSystemMaterial; + exports.Path = Path; + exports.PerspectiveCamera = PerspectiveCamera; + exports.Plane = Plane; + exports.PlaneBufferGeometry = PlaneBufferGeometry; + exports.PlaneGeometry = PlaneGeometry; + exports.PlaneHelper = PlaneHelper; + exports.PointCloud = PointCloud; + exports.PointCloudMaterial = PointCloudMaterial; + exports.PointLight = PointLight; + exports.PointLightHelper = PointLightHelper; + exports.Points = Points; + exports.PointsMaterial = PointsMaterial; + exports.PolarGridHelper = PolarGridHelper; + exports.PolyhedronBufferGeometry = PolyhedronBufferGeometry; + exports.PolyhedronGeometry = PolyhedronGeometry; + exports.PositionalAudio = PositionalAudio; + exports.PropertyBinding = PropertyBinding; + exports.PropertyMixer = PropertyMixer; + exports.QuadraticBezierCurve = QuadraticBezierCurve; + exports.QuadraticBezierCurve3 = QuadraticBezierCurve3; + exports.Quaternion = Quaternion; + exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack; + exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant; + exports.REVISION = REVISION; + exports.RGBADepthPacking = RGBADepthPacking; exports.RGBAFormat = RGBAFormat; - exports.LuminanceFormat = LuminanceFormat; - exports.LuminanceAlphaFormat = LuminanceAlphaFormat; - exports.RGBEFormat = RGBEFormat; - exports.DepthFormat = DepthFormat; - exports.DepthStencilFormat = DepthStencilFormat; - exports.RedFormat = RedFormat; - exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format; - exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format; - exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format; - exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format; - exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format; - exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format; - exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format; - exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format; - exports.RGB_ETC1_Format = RGB_ETC1_Format; + exports.RGBAIntegerFormat = RGBAIntegerFormat; + exports.RGBA_ASTC_10x10_Format = RGBA_ASTC_10x10_Format; + exports.RGBA_ASTC_10x5_Format = RGBA_ASTC_10x5_Format; + exports.RGBA_ASTC_10x6_Format = RGBA_ASTC_10x6_Format; + exports.RGBA_ASTC_10x8_Format = RGBA_ASTC_10x8_Format; + exports.RGBA_ASTC_12x10_Format = RGBA_ASTC_12x10_Format; + exports.RGBA_ASTC_12x12_Format = RGBA_ASTC_12x12_Format; exports.RGBA_ASTC_4x4_Format = RGBA_ASTC_4x4_Format; exports.RGBA_ASTC_5x4_Format = RGBA_ASTC_5x4_Format; exports.RGBA_ASTC_5x5_Format = RGBA_ASTC_5x5_Format; @@ -48181,73 +50830,156 @@ exports.RGBA_ASTC_8x5_Format = RGBA_ASTC_8x5_Format; exports.RGBA_ASTC_8x6_Format = RGBA_ASTC_8x6_Format; exports.RGBA_ASTC_8x8_Format = RGBA_ASTC_8x8_Format; - exports.RGBA_ASTC_10x5_Format = RGBA_ASTC_10x5_Format; - exports.RGBA_ASTC_10x6_Format = RGBA_ASTC_10x6_Format; - exports.RGBA_ASTC_10x8_Format = RGBA_ASTC_10x8_Format; - exports.RGBA_ASTC_10x10_Format = RGBA_ASTC_10x10_Format; - exports.RGBA_ASTC_12x10_Format = RGBA_ASTC_12x10_Format; - exports.RGBA_ASTC_12x12_Format = RGBA_ASTC_12x12_Format; - exports.LoopOnce = LoopOnce; - exports.LoopRepeat = LoopRepeat; - exports.LoopPingPong = LoopPingPong; - exports.InterpolateDiscrete = InterpolateDiscrete; - exports.InterpolateLinear = InterpolateLinear; - exports.InterpolateSmooth = InterpolateSmooth; - exports.ZeroCurvatureEnding = ZeroCurvatureEnding; - exports.ZeroSlopeEnding = ZeroSlopeEnding; - exports.WrapAroundEnding = WrapAroundEnding; - exports.TrianglesDrawMode = TrianglesDrawMode; - exports.TriangleStripDrawMode = TriangleStripDrawMode; - exports.TriangleFanDrawMode = TriangleFanDrawMode; - exports.LinearEncoding = LinearEncoding; - exports.sRGBEncoding = sRGBEncoding; - exports.GammaEncoding = GammaEncoding; + exports.RGBA_BPTC_Format = RGBA_BPTC_Format; + exports.RGBA_ETC2_EAC_Format = RGBA_ETC2_EAC_Format; + exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format; + exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format; + exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format; + exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format; + exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format; + exports.RGBDEncoding = RGBDEncoding; exports.RGBEEncoding = RGBEEncoding; - exports.LogLuvEncoding = LogLuvEncoding; - exports.RGBM7Encoding = RGBM7Encoding; + exports.RGBEFormat = RGBEFormat; + exports.RGBFormat = RGBFormat; + exports.RGBIntegerFormat = RGBIntegerFormat; exports.RGBM16Encoding = RGBM16Encoding; - exports.RGBDEncoding = RGBDEncoding; - exports.BasicDepthPacking = BasicDepthPacking; - exports.RGBADepthPacking = RGBADepthPacking; + exports.RGBM7Encoding = RGBM7Encoding; + exports.RGB_ETC1_Format = RGB_ETC1_Format; + exports.RGB_ETC2_Format = RGB_ETC2_Format; + exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format; + exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format; + exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format; + exports.RGFormat = RGFormat; + exports.RGIntegerFormat = RGIntegerFormat; + exports.RawShaderMaterial = RawShaderMaterial; + exports.Ray = Ray; + exports.Raycaster = Raycaster; + exports.RectAreaLight = RectAreaLight; + exports.RedFormat = RedFormat; + exports.RedIntegerFormat = RedIntegerFormat; + exports.ReinhardToneMapping = ReinhardToneMapping; + exports.RepeatWrapping = RepeatWrapping; + exports.ReplaceStencilOp = ReplaceStencilOp; + exports.ReverseSubtractEquation = ReverseSubtractEquation; + exports.RingBufferGeometry = RingBufferGeometry; + exports.RingGeometry = RingGeometry; + exports.SRGB8_ALPHA8_ASTC_10x10_Format = SRGB8_ALPHA8_ASTC_10x10_Format; + exports.SRGB8_ALPHA8_ASTC_10x5_Format = SRGB8_ALPHA8_ASTC_10x5_Format; + exports.SRGB8_ALPHA8_ASTC_10x6_Format = SRGB8_ALPHA8_ASTC_10x6_Format; + exports.SRGB8_ALPHA8_ASTC_10x8_Format = SRGB8_ALPHA8_ASTC_10x8_Format; + exports.SRGB8_ALPHA8_ASTC_12x10_Format = SRGB8_ALPHA8_ASTC_12x10_Format; + exports.SRGB8_ALPHA8_ASTC_12x12_Format = SRGB8_ALPHA8_ASTC_12x12_Format; + exports.SRGB8_ALPHA8_ASTC_4x4_Format = SRGB8_ALPHA8_ASTC_4x4_Format; + exports.SRGB8_ALPHA8_ASTC_5x4_Format = SRGB8_ALPHA8_ASTC_5x4_Format; + exports.SRGB8_ALPHA8_ASTC_5x5_Format = SRGB8_ALPHA8_ASTC_5x5_Format; + exports.SRGB8_ALPHA8_ASTC_6x5_Format = SRGB8_ALPHA8_ASTC_6x5_Format; + exports.SRGB8_ALPHA8_ASTC_6x6_Format = SRGB8_ALPHA8_ASTC_6x6_Format; + exports.SRGB8_ALPHA8_ASTC_8x5_Format = SRGB8_ALPHA8_ASTC_8x5_Format; + exports.SRGB8_ALPHA8_ASTC_8x6_Format = SRGB8_ALPHA8_ASTC_8x6_Format; + exports.SRGB8_ALPHA8_ASTC_8x8_Format = SRGB8_ALPHA8_ASTC_8x8_Format; + exports.Scene = Scene; + exports.SceneUtils = SceneUtils; + exports.ShaderChunk = ShaderChunk; + exports.ShaderLib = ShaderLib; + exports.ShaderMaterial = ShaderMaterial; + exports.ShadowMaterial = ShadowMaterial; + exports.Shape = Shape; + exports.ShapeBufferGeometry = ShapeBufferGeometry; + exports.ShapeGeometry = ShapeGeometry; + exports.ShapePath = ShapePath; + exports.ShapeUtils = ShapeUtils; + exports.ShortType = ShortType; + exports.Skeleton = Skeleton; + exports.SkeletonHelper = SkeletonHelper; + exports.SkinnedMesh = SkinnedMesh; + exports.SmoothShading = SmoothShading; + exports.Sphere = Sphere; + exports.SphereBufferGeometry = SphereBufferGeometry; + exports.SphereGeometry = SphereGeometry; + exports.Spherical = Spherical; + exports.SphericalHarmonics3 = SphericalHarmonics3; + exports.Spline = Spline; + exports.SplineCurve = SplineCurve; + exports.SplineCurve3 = SplineCurve3; + exports.SpotLight = SpotLight; + exports.SpotLightHelper = SpotLightHelper; + exports.SpotLightShadow = SpotLightShadow; + exports.Sprite = Sprite; + exports.SpriteMaterial = SpriteMaterial; + exports.SrcAlphaFactor = SrcAlphaFactor; + exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor; + exports.SrcColorFactor = SrcColorFactor; + exports.StaticCopyUsage = StaticCopyUsage; + exports.StaticDrawUsage = StaticDrawUsage; + exports.StaticReadUsage = StaticReadUsage; + exports.StereoCamera = StereoCamera; + exports.StreamCopyUsage = StreamCopyUsage; + exports.StreamDrawUsage = StreamDrawUsage; + exports.StreamReadUsage = StreamReadUsage; + exports.StringKeyframeTrack = StringKeyframeTrack; + exports.SubtractEquation = SubtractEquation; + exports.SubtractiveBlending = SubtractiveBlending; + exports.TOUCH = TOUCH; exports.TangentSpaceNormalMap = TangentSpaceNormalMap; - exports.ObjectSpaceNormalMap = ObjectSpaceNormalMap; - exports.CubeGeometry = BoxGeometry; - exports.Face4 = Face4; - exports.LineStrip = LineStrip; - exports.LinePieces = LinePieces; - exports.MeshFaceMaterial = MeshFaceMaterial; - exports.MultiMaterial = MultiMaterial; - exports.PointCloud = PointCloud; - exports.Particle = Particle; - exports.ParticleSystem = ParticleSystem; - exports.PointCloudMaterial = PointCloudMaterial; - exports.ParticleBasicMaterial = ParticleBasicMaterial; - exports.ParticleSystemMaterial = ParticleSystemMaterial; - exports.Vertex = Vertex; - exports.DynamicBufferAttribute = DynamicBufferAttribute; - exports.Int8Attribute = Int8Attribute; - exports.Uint8Attribute = Uint8Attribute; - exports.Uint8ClampedAttribute = Uint8ClampedAttribute; - exports.Int16Attribute = Int16Attribute; + exports.TetrahedronBufferGeometry = TetrahedronBufferGeometry; + exports.TetrahedronGeometry = TetrahedronGeometry; + exports.TextBufferGeometry = TextBufferGeometry; + exports.TextGeometry = TextGeometry; + exports.Texture = Texture; + exports.TextureLoader = TextureLoader; + exports.TorusBufferGeometry = TorusBufferGeometry; + exports.TorusGeometry = TorusGeometry; + exports.TorusKnotBufferGeometry = TorusKnotBufferGeometry; + exports.TorusKnotGeometry = TorusKnotGeometry; + exports.Triangle = Triangle; + exports.TriangleFanDrawMode = TriangleFanDrawMode; + exports.TriangleStripDrawMode = TriangleStripDrawMode; + exports.TrianglesDrawMode = TrianglesDrawMode; + exports.TubeBufferGeometry = TubeBufferGeometry; + exports.TubeGeometry = TubeGeometry; + exports.UVMapping = UVMapping; exports.Uint16Attribute = Uint16Attribute; - exports.Int32Attribute = Int32Attribute; + exports.Uint16BufferAttribute = Uint16BufferAttribute; exports.Uint32Attribute = Uint32Attribute; - exports.Float32Attribute = Float32Attribute; - exports.Float64Attribute = Float64Attribute; - exports.ClosedSplineCurve3 = ClosedSplineCurve3; - exports.SplineCurve3 = SplineCurve3; - exports.Spline = Spline; - exports.AxisHelper = AxisHelper; - exports.BoundingBoxHelper = BoundingBoxHelper; - exports.EdgesHelper = EdgesHelper; + exports.Uint32BufferAttribute = Uint32BufferAttribute; + exports.Uint8Attribute = Uint8Attribute; + exports.Uint8BufferAttribute = Uint8BufferAttribute; + exports.Uint8ClampedAttribute = Uint8ClampedAttribute; + exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute; + exports.Uniform = Uniform; + exports.UniformsLib = UniformsLib; + exports.UniformsUtils = UniformsUtils; + exports.UnsignedByteType = UnsignedByteType; + exports.UnsignedInt248Type = UnsignedInt248Type; + exports.UnsignedIntType = UnsignedIntType; + exports.UnsignedShort4444Type = UnsignedShort4444Type; + exports.UnsignedShort5551Type = UnsignedShort5551Type; + exports.UnsignedShort565Type = UnsignedShort565Type; + exports.UnsignedShortType = UnsignedShortType; + exports.VSMShadowMap = VSMShadowMap; + exports.Vector2 = Vector2; + exports.Vector3 = Vector3; + exports.Vector4 = Vector4; + exports.VectorKeyframeTrack = VectorKeyframeTrack; + exports.Vertex = Vertex; + exports.VertexColors = VertexColors; + exports.VideoTexture = VideoTexture; + exports.WebGL1Renderer = WebGL1Renderer; + exports.WebGLCubeRenderTarget = WebGLCubeRenderTarget; + exports.WebGLMultisampleRenderTarget = WebGLMultisampleRenderTarget; + exports.WebGLRenderTarget = WebGLRenderTarget; + exports.WebGLRenderTargetCube = WebGLRenderTargetCube; + exports.WebGLRenderer = WebGLRenderer; + exports.WebGLUtils = WebGLUtils; + exports.WireframeGeometry = WireframeGeometry; exports.WireframeHelper = WireframeHelper; + exports.WrapAroundEnding = WrapAroundEnding; exports.XHRLoader = XHRLoader; - exports.BinaryTextureLoader = BinaryTextureLoader; - exports.GeometryUtils = GeometryUtils; - exports.Projector = Projector; - exports.CanvasRenderer = CanvasRenderer; - exports.SceneUtils = SceneUtils; - exports.LensFlare = LensFlare; + exports.ZeroCurvatureEnding = ZeroCurvatureEnding; + exports.ZeroFactor = ZeroFactor; + exports.ZeroSlopeEnding = ZeroSlopeEnding; + exports.ZeroStencilOp = ZeroStencilOp; + exports.sRGBEncoding = sRGBEncoding; Object.defineProperty(exports, '__esModule', { value: true });